ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

苍穹外卖DAY6:微信小程序登录与商品浏览实现详解

苍穹外卖DAY6:微信小程序登录与商品浏览实现详解 都在说苍穹外卖这种练手项目难度不够、没什么含金量但真到了DAY6你会发现这一天几乎是整个项目里最容易卡住的一天。前面几天你都在SpringBoot管理端里自娱自乐接口给前端调、数据从库里查一切都挺顺手。到了微信小程序这块事情突然变成了前端调你、你调微信、微信再给你回数据的三方协作HttpClient、微信登录、小程序页面全部搅在一起稍不留神就卡在某个莫名其妙的报错上出不来。这篇文章就把DAY6的完整实现过程捋一遍。从后端为什么要用HttpClient到小程序怎么搭基础页面再到微信登录的完整链路、商品浏览功能的代码导入每个环节都给出可落地的代码和注意事项希望对正在敲这个项目的同学有帮助。1. 项目概述与DAY6的阶段目标1.1 苍穹外卖项目到底在做什么苍穹外卖是一个对标美团、饿了么的外卖平台练手项目整体分成管理端和用户端两大块。管理端跑在浏览器里是给平台运营和商家用的负责员工管理、分类管理、菜品管理、订单处理这些后台操作用户端则是微信小程序给真实消费者用的用户打开小程序浏览商品、下单、支付、查看订单。DAY6是整个项目的一个分水岭。前面5天你折腾的基本都是管理端技术栈相对纯粹SpringBoot、MyBatis、Redis、JWT这些后端常规操作。但到了DAY6视角一下子切换到用户端而且第一次引入微信生态处理的问题从管理数据变成了跟微信服务器打交道。这一天要做的核心事情可以概括成一句话让用户打开小程序后能够通过微信身份完成登录然后顺畅地浏览商品分类和商品列表。听起来简单实际做起来牵扯的东西可不少——后端要主动发起HTTP请求去调微信接口前端要搭建小程序页面框架两边还要通过一套登录流程打通身份验证。1.2 DAY6的核心任务拆解我把DAY6的内容拆成了四个相互关联的子任务按照开发顺序来看会非常清晰引入HttpClient并在后端调用微信接口小程序端通过wx.login只能拿到一个临时的code后端必须拿这个code去请求微信的jscode2session接口才能换回用户的openid。这个后端主动请求第三方接口的能力就是HttpClient要解决的。搭建微信小程序开发环境和页面框架小程序端不是零基础上手需要熟悉它的目录结构、页面组成、以及和传统网页开发的差异。基础架子搭得好后面写业务页面会快很多。实现微信登录的完整闭环从前端wx.login拿code到后端换openid、查库建用户、签发JWT再到前端保存token、后续请求携带token这条链路是用户端所有业务功能的地基。导入商品浏览功能代码把管理端已经建好的分类和商品数据通过新的接口维度暴露给小程序端让用户能按分类浏览启售状态的商品列表。这四块内容环环相扣登录是前提商品浏览是第一个真正面向用户的功能页面HttpClient则是连接前后端和微信三方的一座桥。2. HttpClient后端调用第三方接口的敲门砖2.1 为什么后端需要HttpClient前5天写SpringBoot后端你接触最多的是别人请求我——管理端前端发HTTP请求后端Controller接住、处理、返回。但DAY6突然出现了一个相反的需求后端需要主动去请求别人这里的别人就是微信服务器。场景是这样的用户在小程序里点击登录小程序端调用wx.login()拿到一个临时凭证code。但这个code本身没有任何用户身份信息想拿到用户的openid必须由后端拿着这个code去请求微信官方接口。也就是说后端这时候要扮演客户端的角色主动发一次HTTP请求。Java里发起HTTP请求的方式其实不少原生的HttpURLConnection能用但代码啰嗦RestTemplate功能强但配置略重。苍穹外卖项目里用的是Hutool工具包中的HttpUtil它是对Apache HttpClient的深度封装把HTTP请求简化到了极致——不需要创建复杂的配置对象不需要管理连接池一个静态方法调用就能搞定GET或POST请求。我在其他项目里也经常用Hutool的HttpUtil最大的感受就是它对新手特别友好不用理解HTTP协议细节就能上手。但后面我会单独说这种好用是有代价的等到了生产环境你还是要回来理解底层原理。2.2 引入依赖与基础配置首先要在sky-server模块的pom.xml里引入Hutool依赖dependency groupIdcn.hutool/groupId artifactIdhutool-all/artifactId version5.8.16/version /dependency引入依赖后先做一个最基础的自测。随便找一个公开接口用HttpUtil发起一次GET请求确认环境没问题String url https://www.example.com/api; String result HttpUtil.get(url); System.out.println(result);这里有一个很容易踩的坑Hutool的HttpUtil默认使用的是HTTP协议如果url没写协议头会直接报错。另外微信的接口都是HTTPS的Hutool会自动处理SSL证书验证这一点比原生的HttpURLConnection省心很多——原生方式调用HTTPS接口经常会遇到证书信任问题还得手动绕过证书验证那代码写起来简直灾难。2.3 调用微信jscode2session接口的实现DAY6里HttpClient的核心应用是调用微信的登录凭证校验接口也就是jscode2session。接口信息如下请求地址https://api.weixin.qq.com/sns/jscode2session请求方式GET请求参数appid小程序唯一标识、secret小程序密钥、js_code前端传来的临时凭证、grant_type固定值authorization_code返回结果openid用户唯一标识、session_key会话密钥、errcode和errmsg异常时返回后端代码实现如下// 根据code调用微信接口获取openid private String getOpenid(String code) { // 构造请求参数 MapString, Object paramMap new HashMap(); paramMap.put(appid, weChatProperties.getAppid()); paramMap.put(secret, weChatProperties.getSecret()); paramMap.put(js_code, code); paramMap.put(grant_type, authorization_code); // 调用微信接口 String url https://api.weixin.qq.com/sns/jscode2session; String json HttpUtil.get(url, paramMap); // 解析返回结果 JSONObject jsonObject JSONUtil.parseObj(json); String openid jsonObject.getStr(openid); return openid; }这段代码看起来简单但有几个细节必须注意appid和secret不要硬编码项目里通常用ConfigurationProperties方式注入WeChatProperties配置写在application.yml里方便不同环境切换。响应必须判空如果code无效或者被使用过微信接口返回的JSON里没有openid字段而是有errcode和errmsg。直接取openid会拿到null。code是一次性的同一个code只能调用一次jscode2session第二次调用会报40029或40163错误。所以前端拿code、传code、后端换openid这条链路要一气呵成。2.4 HttpClient使用过程中的三个教训Hutool的HttpUtil虽然上手简单但用的时间长了我也踩过几次坑这里拿出来给大家提个醒。第一超时一定要设置。HttpUtil.get默认是无限等待的如果微信接口因为网络问题响应很慢后端线程会一直被占用并发高的时候很容易把线程池打满。我一般会通过配置HttpRequest来设置连接超时和读取超时String result HttpRequest.get(url) .form(paramMap) .timeout(10000) // 连接和读取都设置10秒超时 .execute() .body();第二Hutool会自动做参数URL编码这个在大部分场景下是好事但如果你传的参数值里本身有已经编码好的内容会出现双重编码问题。好在jscode2session接口的参数都是纯字母数字目前不用操心这个。第三生产环境建议还是用Spring的RestTemplate或者OpenFeign而不是直接散落调用Hutool。Hutool的HttpUtil不适合做连接池管理每次请求重建连接在高并发场景下性能和稳定性都不如专门的HTTP客户端。练手项目可以用它快速实现但要有这个意识。3. 微信小程序开发环境与项目搭建3.1 小程序前端与传统网页开发的差异很多同学第一次接触小程序就是在DAY6如果之前只有Vue或React的基础肯定会有一些不适应。小程序虽然也写JS和CSS但有几个核心差异需要花点时间去适应没有DOM和BOM小程序运行在自己的渲染层不能直接操作DOM节点所有界面更新都是通过数据绑定自动完成的。你改数据页面就变这是数据驱动视图的思维。页面由四个文件组成同一个页面目录下会有.wxml模板、.wxss样式、.js逻辑、.json配置四个文件职责划分非常明确。样式单位用rpxrpx是小程序特有的响应式像素单位屏幕宽度固定为750rpx不同机型会自动换算。写页面时用rpx可以省去大量适配工作。3.2 小程序端目录结构与初始化配置苍穹外卖的小程序前端目录结构大致是这样的sky-take-out-miniprogram/ ├── pages/ │ ├── index/ // 首页 │ ├── category/ // 分类页面 │ ├── product/ // 商品详情 │ ├── login/ // 登录页 │ └── user/ // 个人中心 ├── utils/ │ └── request.js // 请求封装 ├── app.js // 全局入口 ├── app.json // 全局配置 └── project.config.json // 项目配置有一个经常被忽略但很关键的文件是app.json它配置了小程序的页面路由、窗口样式和tabBar。新增页面时必须在pages数组里注册否则跳转会白屏。我当时在这个坑里浪费了不少时间切换页面一直报页面路径不正确最后发现是忘记注册路由了。小程序里每个页面的.js文件有一个核心配置对象Page()包含data页面数据、onLoad页面加载生命周期、onShow页面显示生命周期以及各种事件处理函数。数据绑定则通过WXML里的模板语法完成比如{{productList}}修改数据用this.setData({ productList: list })。3.3 封装小程序请求工具小程序发送HTTP请求用的API是wx.request。但每个页面都直接写wx.request会非常痛苦——baseURL要写很多遍、token要手动加、错误要每个页面自己处理。项目里通常会在utils/request.js中统一封装一层。我当时的封装思路是把baseURL抽成常量请求时自动从本地存储读取token并添加到header响应时统一做code判断失败弹Toast提示关键是把整个请求封装成Promise这样页面里就能用async/await写出非常清爽的代码// utils/request.js const BASE_URL http://localhost:8080; function request({ url, method GET, data {} }) { return new Promise((resolve, reject) { const token wx.getStorageSync(token); wx.request({ url: BASE_URL url, method: method, data: data, header: { Content-Type: application/json, Authorization: token ? Bearer ${token} : }, success: (res) { if (res.statusCode 200) { resolve(res.data); } else if (res.statusCode 401) { // token失效跳转登录 wx.navigateTo({ url: /pages/login/login }); } else { wx.showToast({ title: res.data.msg || 请求失败, icon: none }); reject(res); } }, fail: (err) { wx.showToast({ title: 网络异常, icon: none }); reject(err); } }); }); } module.exports { request, BASE_URL };这里有个开发环境的关键设置。用微信开发者工具调试本地后端接口时默认会拦截非HTTPS域名。必须在本地设置里勾选不校验合法域名、web-view(业务域名)、TLS版本以及HTTPS证书否则请求根本发不出去。这也是新手最容易卡住的地方打开开发者工具第一件事就应该把这个选项勾上。4. 微信登录从零到一完整实现4.1 微信登录整体流程梳理微信登录是整个DAY6最核心的部分它把前端小程序、后端服务、微信服务器三者串在了一条链路上。我在纸上画了很多遍这个流程这里用文字完整还原一遍用户打开小程序前端调用wx.login()微信返回一个临时凭证code。前端把code通过wx.request发送到后端自己的接口比如POST /user/login。后端收到code后通过HttpClient调用微信的jscode2session接口传入appid、secret、code。微信服务器校验通过返回这个用户对应的openid和session_key。后端拿着openid去数据库的user表查记录。查不到就创建一个新用户查到了就直接用。后端根据用户ID生成JWT令牌把openid和userId放到令牌负载里。后端把JWT返回给小程序端。小程序端拿到JWT存入本地缓存之后每次请求都通过Authorization头携带这个token。理解这个流程的关键在于小程序端自始至终没有直接接触微信的用户身份数据微信服务器只认后端后端把自己的appid和secret作为门禁卡去换用户身份再把身份转成自己系统的token发给前端。这套设计保证了secret不会暴露在小程序代码里而小程序代码本质上是可以被完全逆向的。4.2 后端登录接口完整实现后端代码分成三层以注释的方式体现关键逻辑RestController RequestMapping(/user) Slf4j public class UserController { Autowired private UserService userService; PostMapping(/login) public ResultUserLoginVO login(RequestBody UserLoginDTO userLoginDTO) { log.info(微信用户登录code:{}, userLoginDTO.getCode()); // 1. 获取用户信息openid User user userService.wxLogin(userLoginDTO); // 2. 生成JWT令牌 MapString, Object claims new HashMap(); claims.put(userId, user.getId()); String token JwtUtil.createJWT(claims); // 3. 封装返回结果 UserLoginVO userLoginVO UserLoginVO.builder() .id(user.getId()) .openid(user.getOpenid()) .token(token) .build(); return Result.success(userLoginVO); } }Service层的实现核心是微信接口调用和用户判断public User wxLogin(UserLoginDTO userLoginDTO) { // 1. 调用微信接口获取openid String openid getOpenid(userLoginDTO.getCode()); if (openid null) { throw new LoginFailedException(微信登录失败请重试); } // 2. 根据openid查询用户 User user userMapper.getByOpenid(openid); if (user null) { // 3. 新用户则自动注册 user User.builder() .openid(openid) .createTime(LocalDateTime.now()) .updateTime(LocalDateTime.now()) .build(); userMapper.insert(user); } return user; }有一个细节需要注意Day6阶段新用户默认没有用户名、手机号、头像这些资料先用openid创建一条最小记录后续可以在个人中心里补充完善。不要想着一次性把用户信息全收齐微信登录本来就允许用户先登录后完善资料。4.3 JWT签发与登录状态管理JWT在DAY6里扮演的角色非常关键。微信登录成功后后端不再像管理端那样每次请求都带sessionId而是把用户身份信息编码进一个自包含的令牌里前端每次请求携带后端校验通过就认为是可信用户。JwtUtil工具类的核心方法public static String createJWT(MapString, Object claims) { // 设置签发时间、过期时间、签名算法 JwtBuilder builder Jwts.builder() .setClaims(claims) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() 7200000)) .signWith(SignatureAlgorithm.HS256, secretKey); return builder.compact(); } public static Claims parseJWT(String jwt) { return Jwts.parser() .setSigningKey(secretKey) .parseClaimsJws(jwt) .getBody(); }过期时间我见过设1小时的也见过设7天的。外卖场景建议设2小时左右配合前端的自动重新登录兼顾体验和安全性。JWT的密钥一定要放在配置文件中而且不要用默认的字符串生产环境建议用足够长的随机字符串。4.4 前端小程序登录逻辑小程序端的登录逻辑放在utils里核心代码如下function wxLogin() { return new Promise((resolve, reject) { // 1. 获取微信登录code wx.login({ success: async (res) { if (res.code) { try { // 2. 把code发给后端 const data await request({ url: /user/login, method: POST, data: { code: res.code } }); // 3. 保存token和用户信息 wx.setStorageSync(token, data.data.token); wx.setStorageSync(userInfo, data.data); resolve(data); } catch (err) { reject(err); } } }, fail: (err) reject(err) }); }); }很多同学会在登录时纠结要不要在onLaunch里就调登录我的做法是不着急调在用户第一次需要身份信息或后端返回401时再去调。Day6阶段商品浏览其实不需要登录就能看但下单、购物车这些功能才必须登录。按需登录可以减少不必要的请求。另外有一个常见坑wx.login的code是5分钟内有效且只能用一次如果你在onLaunch里调了一次登录后面某个页面又调了一次第一个请求回来时发现code已经失效就会报错。所以我建议用Promise封装登录方法保证全局只有一个登录请求在进行。5. 导入商品浏览功能代码解析5.1 商品浏览的需求分析商品浏览是DAY6里最看得见的功能用户打开小程序就能看到。它的核心交互场景是首页顶部展示所有启用的分类用户点击左侧分类右侧就展示该分类下所有启售中的商品。这个功能在管理端已经有了基础的分类和商品管理接口但用户端的接口设计和管理端有几个明显的不同只查启用的分类管理端可以查到禁用状态的分类用户端必须过滤掉。只查启售的商品如果商家把某个商品停售了用户端不能再看到更不能下单。返回结构更适合展示用户端接口返回的商品信息未必需要管理端那些复杂的字段比如创建时间、更新时间、操作日志等用户端只需要id、名称、图片、价格、描述、销量这些核心字段。5.2 分类与商品查询接口实现后端新增两个ControllerCategoryController提供用户端分类查询接口RestController RequestMapping(/user/category) public class UserCategoryController { Autowired private CategoryService categoryService; GetMapping(/list) public ResultListCategory list(Integer type) { // 只查询启用状态的分类 ListCategory list categoryService.listByStatus(1, type); return Result.success(list); } }ProductController提供用户端商品列表查询接口RestController RequestMapping(/user/product) public class UserProductController { Autowired private ProductService productService; GetMapping(/list) public ResultListProductVO list(Long categoryId) { // 根据分类查启售商品 ListProductVO list productService.listByCategoryId(categoryId); return Result.success(list); } }Service层的关键SQL逻辑用注解方式写在Mapper接口里Select(SELECT * FROM product WHERE category_id #{categoryId} AND status 1 ORDER BY sort DESC, create_time DESC) ListProduct listByCategoryId(Long categoryId);这里有个特别容易被忽略的点商品列表查出来之后如果商品有口味比如辣度、加料选择需要在返回之前查询并封装进ProductVO。因为用户点商品的时候要选择口味才能加购物车这一步不做后面下单功能会很麻烦。关联查询的代码一定要放在Service层不能在Controller里写业务逻辑否则后续加缓存、加校验、加日志的时候Controller会越来越臃肿。5.3 小程序端商品展示实现前端首页的商品展示结构核心是一个scroll-view左右联动布局左侧是分类列表右侧是当前分类下的商品列表。交互逻辑集中在三个地方进入页面时先请求分类列表默认选中第一个分类点击左侧分类更新选中状态重新请求右侧商品列表右侧商品列表支持下拉刷新加载更多用分页页面逻辑的核心代码Page({ data: { categories: [], currentCategoryId: null, products: [], loading: false }, onLoad() { this.loadCategories(); }, async loadCategories() { const res await request({ url: /user/category/list, data: { type: 1 } }); const categories res.data; this.setData({ categories }); if (categories.length 0) { // 默认选中第一个分类并加载商品 this.setData({ currentCategoryId: categories[0].id }); this.loadProducts(categories[0].id); } }, async loadProducts(categoryId) { this.setData({ loading: true }); try { const res await request({ url: /user/product/list, data: { categoryId } }); this.setData({ products: res.data }); } finally { this.setData({ loading: false }); } }, onCategoryTap(e) { const id e.currentTarget.dataset.id; if (id this.data.currentCategoryId) return; this.setData({ currentCategoryId: id }); this.loadProducts(id); } });这里有一个非常重要的联调经验商品图片如果在数据库里存的是后端服务器上的相对路径比如/images/product/1.jpg小程序端直接用是加载不出来的必须拼接上后端的访问域名或IP。我当时在项目里是在后端返回时直接拼好完整URL路径如果图片存的是MinIO或OSS那也是同样处理返回可访问的完整URL。这一步不做页面渲染出来就是一堆裂图。6. 常见问题与排查技巧实录6.1 微信登录的经典报错与排查微信登录这个功能前端后端联调时绝对会让你掉几层头发。我挑几个最常见的错误码和排查思路错误码40029code无效这个code要么已经过期5分钟有效期要么已经被使用过一次。排查思路是先看是不是前端重复调用了wx.login或者是同一个code被发送了多次请求。可以在后端加日志打印收到的code和时间跟微信返回的errcode对照着排查。错误码40163code已被使用过出现这个错误说明同一个code被调用了两次jscode2session。为什么会调用两次最常见的是前端发请求时网络超时前端重试了一次但第一次请求其实已经到达了后端并成功调用了微信接口。换句话说重复请求导致code被消费了两次。解决办法是前端不要把登录请求做自动重试如果用户手动触发多次登录后端要做幂等处理。返回openid为null大概率是appid或secret配置错了先核对application.yml里的配置和后端实际注入的值。还有一个小坑复制粘贴配置文件时YAML的缩进不对会导致配置解析不出来检查一下appid、secret前面有没有对不齐的空格。登录成功后查询用户信息时抛异常新用户创建后查询用户信息的时机不要太早。因为用户可能还没跑到个人中心数据库里可能还没有完整的用户资料查询时要做空值判断或者干脆以openid为维度做最小化查询。6.2 HttpClient和接口调用踩坑记录后端调用微信接口这块我总结了自己和身边同学踩过的三四次坑第一响应解析时序问题。HttpUtil.get返回的JSON解析时直接调getStr(openid)如果微信返回了errcode但没返回openid这里得到的就是null。不要在Controller层直接拿这个null去查库否则MyBatis会报无效的列类型之类的错。正确的做法是在Service层判空抛业务异常由全局异常处理器统一返回友好提示。第二参数拼接问题。Hutool的HttpUtil.get支持传入Map参数自动拼URL这个好用但要注意Map的key不要写错。js_code这个参数名非常容易写成jsCode微信接口是下划线风格写错了直接返回400错误。小程序端传参时可以随便用驼峰但后端调微信接口时必须按微信文档的参数名来。第三请求时机问题。微信接口的网络延迟不是我们能控制的日志里一定要记录耗时。我遇到过一个问题后端调用微信接口平均耗时1.5秒前端请求超时设了2秒结果用户感觉登录时好时坏。后来把超时时间放宽到10秒并把wx.login和用户资料请求并行发起体验才好起来。6.3 小程序联调问题总结小程序端的联调问题一部分源于开发者工具使用不熟练一部分源于前后端对接口的定义不一致。开发者工具勾了不校验合法域名还是请求失败检查一下你的请求URL是不是写错了协议头。本地后端是http如果前面不小心写了https本地开发时一样会失败。另外要确认后端启动的端口苍穹外卖默认8080如果被占用改成了别的端口前端baseURL记得同步改。请求报跨域错误小程序平台的wx.request其实不存在传统浏览器的跨域限制但你如果在开发者工具的模拟器里调试H5页面或者把接口地址配到了web-view里就会遇到跨域问题。后端Controller上加CrossOrigin注解能解决大部分情况但更规范的做法是在网关或Nginx层统一配置跨域。商品图片裂图前面说过图片路径如果是相对路径要拼接后端访问地址。还有一个坑是图片路径存的是D:\images\product\1.jpg这种本地绝对路径这种在生产环境完全没法用。建议项目里统一封装一个方法处理图片URL把本地存储、MinIO、OSS等不同情况的路径都转成可访问的完整URL前端就不用关心图片存在哪了。数据库中文乱码这个坑与商品浏览功能密切相关。商品名称、分类名称这些中文数据如果数据库连接的characterEncoding没配置utf8小程序端就会显示乱码。检查一下数据库连接URL里有没有characterEncodingutf8以及数据库表本身是不是utf8mb4编码。之前排查一个商品名称显示一半的问题就是字段长度不够商品名称被截断了报错信息在日志里不明显最后看数据库才发现。7. 商品浏览性能优化与后续扩展方向7.1 加一层Redis缓存商品浏览功能做完只是第一步。有些商品数据几乎不变比如分类列表和商品名称、图片、价格这些基础信息每次小程序端进入首页都实时查库其实是浪费数据库连接。我当时在商品浏览做完后顺手加了一层Redis缓存。思路很清晰查询分类或商品列表时先查Redis命中就直接返回没有命中就去查MySQL查完写入Redis并设置过期时间比如分类缓存设1小时商品列表缓存设30分钟。管理端如果修改了商品数据主动删除对应缓存保证用户端能尽快看到更新。引入缓存之后首页接口的响应时间从80毫秒降到了10毫秒以内虽然数据量小效果不明显但思路一定要有。7.2 商品搜索与分页加载Day6的商品浏览只做到了按分类查询但真实外卖场景用户还需要搜索。给商品的name字段做模糊匹配很简单但如果商品量大直接用LIKE %关键词%会有性能问题。建议引入全文索引或者用Redis的倒排结构做简单搜索企鹅文档里常见的方案是用MyBatis的动态SQL拼接搜索条件和分类条件、启售状态组合查询。另外Day6的商品列表是一次性查完返回的商品数量少没问题但后续肯定要做分页。小程序端用scroll-view触底加载更多后端接口加page和pageSize参数返回结果带total字段前端判断是否还有下一页。7.3 用户端后续功能的衔接商品浏览是用户端的第一块拼图后面接踵而来的购物车、下单、支付、订单列表、个人中心全都依赖Day6打好的两个基础登录态和商品数据接口。说句实在话很多同学学到后面订单支付那块写不下去回头发现最根本的原因是Day6登录链路没理解透——token不知道在哪存、请求头怎么加、后端拦截器怎么校验。所以Day6一定要吃透宁可多花两天搞明白微信登录的原理也不要囫囵吞枣往下冲。我个人在实际操作中还有一个体会DAY6的代码量不一定很大但涉及的知识点非常杂前后端分离的思路第一次真正体现出来。建议在动手写代码之前先用文字把微信登录的完整流程画一遍把每个节点涉及的角色、接口、参数、数据变化都写清楚。把这个流程吃透后面前端联调会顺畅很多。如果中途卡住了优先从网络请求这一步开始排查——先看小程序有没有发出请求再看后端有没有收到再看后端有没有成功调通微信接口一层层往下找。最后再分享一个小技巧把后端日志的SQL和执行时间打开联调时能看到每次请求实际执行了什么语句排查问题时效率直接翻倍。
返回列表