Skip to content

微信小程序网络请求进行二次封装与搭建首页猜你喜欢与热门推荐的(Day3 2/2) ​

本页对应 day3,共 4 段视频,约 1 小时 52 分。

学习目标 ​

  • 能准确描述微信小程序登录完整流程,说明 wx.login 获取临时 code、后端换取用户标识并签发 token、前端持久化 token 并在业务请求中携带的链路。
  • 能完成微信小程序网络请求二次封装,统一请求地址与参数处理,并根据本地 token 动态设置请求头,验证未登录不带 token、登录后自动携带。
  • 能实现编辑模块业务:进入编辑页展示用户头像与昵称,支持修改头像和昵称,调用更新用户信息接口,成功后使用 wx.navigateBack 返回个人中心并在 onShow 重新获取用户信息。
  • 能根据接口文档封装登录授权相关 API,包括获取 token、获取用户信息、更新用户信息,并在页面事件中正确调用及处理成功与失败分支。
  • 能区分并说明用户授权老版本写法(button open-type="getUserInfo"、wx.getUserInfo)的调用方式、废弃原因及新版本头像昵称填写能力,能判断现有小程序是否仍可使用。
  • 能完成首页“猜你喜欢”“热门推荐”和分类页的静态结构与样式搭建,并能说明静态页面与后续逻辑接入的边界。

知识点 ​

为什么要把网络请求封装成函数 ​

为什么需要:小程序里每个页面都可能发请求,如果每个页面都写一遍 wx.request,基础路径、加载提示、成功失败处理就会重复,改一处要改很多地方。转写稿里反复出现“发请求找服务器要用户信息”“请求头要带 token”,说明请求逻辑会反复使用,必须复用。

怎么想:把“发请求”看成一个函数:页面只传 url、method、data,函数内部统一拼基础路径、显示加载、调用 wx.request、返回 Promise。页面拿到的是服务器数据,不关心底层怎么写。

怎么做:用 export default (params) => {} 导出一个函数,函数返回 new Promise,成功 resolve,失败 reject。

易错点:不要把 baseURL 写死在每个页面;不要直接返回 wx.request 的原始结果;注释里的参数示例应写成 {url:'xxxx', method:'post', data:{a:1}},注意逗号。

先想清楚参数和返回值 ​

为什么需要:页面调用时要能控制请求地址、方式、参数;调用后还要能用 .then 或 await 接结果。

怎么想:params.url 是相对路径,params.method 不传就默认 GET,params.data 不传就默认空对象。服务器返回的 res 里真正业务数据通常在 res.data,所以成功时 resolve(res.data)。

怎么做:在 wx.request 里写 url: baseURL + params.url、method: params.method || "GET"、data: params.data || {}。

易错点:url 不要传完整地址再拼一次;method 默认值要写清楚;resolve(res.data) 不要写成 resolve(res),否则页面还要自己剥一层。

封装实现 ​

下面是本节笔记中的封装代码,原样保留:

js
//网络请求全部的页面使用--功能封装函数(复用)
//params:调用函数传递参数 {url:'xxxx'.method:'post',data:{a:1}}
export default (params) => {
    return new Promise((resolve, reject) => {
        //请求基础路径
        const baseURL = 'https://gmall-prod.atguigu.cn'
        //发请求之前加载效果出来
        wx.showLoading({
          title: '加载....',
        })
        //发起网络请求
        wx.request({
            //请求URL----绝对路径
            url: baseURL + params.url,
            //请求方式
            method: params.method || "GET",
            //携带参数
            data: params.data || {},
            //成功回调
            //res即为服务器响应数据
            success(res) {
                //返回一个成功的Promise对象
                //简化数据
                resolve(res.data);
            },
            fail(error) {
                reject(error);
            },
            //成功与失败钩子
            complete(){
                 //加载效果取消
                 wx.hideLoading()
            }
        });
    })
}

为什么需要:这段代码把公共逻辑收在一处,页面只关心业务。

怎么想:showLoading 在请求前显示,complete 在成功或失败后都执行,所以关闭 loading 放 complete 最稳。

怎么做:页面引入后传参调用,例如 req({url:'/api/xxx', method:'POST', data:{...}}),再用 then 接数据。

易错点:showLoading 与 hideLoading 要成对;不要在 success 里关 loading 而漏掉失败场景;fail(error) 要把错误继续抛给页面,不能吞掉。

成功、失败与加载状态 ​

为什么需要:网络请求可能成功也可能失败,页面要能分别处理;加载提示能避免用户重复点击。

怎么想:success 只负责把业务数据交出去,fail 只负责把错误交出去,complete 负责收尾。

怎么做:成功 resolve(res.data),失败 reject(error),收尾 wx.hideLoading()。

易错点:转写稿里“通感/头感/偷看”其实是 token,“扣/库”是 code,“微信点request”是 wx.request。调试时如果打印不到用户信息,先看请求有没有发、请求头有没有带 token;本节封装是基础请求,后续需要登录态的接口应在封装层统一补 header,不要每个页面手写,容易漏。

页面调用与调试 ​

为什么需要:封装不是写完就结束,要验证页面能否拿到数据。

怎么想:先看请求地址是否拼接正确,再看 method 和 data 是否符合接口文档,最后看返回值是不是 res.data。

怎么做:页面里引入封装函数,调用后打印结果;转写稿中调试用户信息时就是先打印 res,发现不带 token 拿不到数据,再补请求头。

易错点:不要把 token 存在临时变量里,转写稿强调要用小程序本地存储持久化;页面跳转和请求时机要分清,onLoad 一般只执行一次,回到页面要刷新数据时要考虑 onShow。这些是使用封装时常见的调试点。

先厘清本节要做什么 ​

本节转写内容实际围绕“微信小程序登录授权、编辑用户资料、更新用户信息”展开。核心链路是:用户点击授权登录 → 前端调用 wx.login 拿临时凭证 code → 前端把 code 发给自己的后台 → 后台携带管理员提供的 AppID、密钥和 code 去微信服务器换 openid/session_key,再生成自定义登录态 token 返回前端 → 前端持久化 token → 后续请求在请求头带 token 获取用户信息。易错点:不要把 AppID、密钥写在前端;code 是一次性的临时凭证;token 才是前端后续业务请求要带的登录态。

第一步:调用 wx.login 拿 code ​

为什么需要:小程序里的用户身份来自微信,前端不能直接拿微信用户资料,必须先通过微信登录能力拿到临时凭证。怎么想:点击“授权登录”按钮后,先不急着跳页面,而是先拿 code,再请求自己后台。怎么做:在按钮事件里调用 wx.login,成功回调里取 res.code,再调用项目封装的登录接口。易错点:code 不是 token,不能直接存起来当登录态;没有拿到 code 就发登录请求,后台无法换用户标识。

js
// 点击授权登录按钮
async handleLogin() {
  const { code } = await wx.login()
  const res = await request('/login', {
    method: 'POST',
    data: { code }
  })
  // res 中应返回后台生成的自定义登录态 token
  if (res.code === 200) {
    wx.setStorageSync('token', res.data.token)
    wx.navigateTo({ url: '/pages/edit/edit' })
  }
}

第二步:持久化 token,并在请求头携带 ​

为什么需要:登录成功后,进入个人中心、购物车、编辑资料等页面都要证明“我是谁”。怎么想:token 只需授权登录成功一次后持久化,后续发请求从本地缓存取。怎么做:用 wx.setStorageSync('token', token) 存,用 wx.getStorageSync('token') 取;封装请求时判断有 token 才加请求头。易错点:请求头不要写成空值;没有 token 时不要强行带;小程序本地存储有容量上限,PC 端上限与移动端不同,课堂提到“1M/5M”要按官方文档确认,不要死记错。

js
const token = wx.getStorageSync('token')
const header = {}
if (token) {
  header.token = token
}

const res = await request('/user/info', {
  method: 'GET',
  header
})

第三步:进入编辑页展示已有用户信息 ​

为什么需要:授权成功后要先展示微信昵称、头像,用户不想改可直接用,想改再编辑。怎么想:编辑页加载时先请求用户信息,再赋值给页面数据。怎么做:在 onLoad 中请求 /user/info,把昵称、头像写入 data。易错点:这个请求必须带 token,否则拿不到数据;头像地址可能是腾讯缓存图,模拟器能显示、真机可能不显示,这是课堂反复强调的真机测试点,不是简单前端语法错。

js
Page({
  data: {
    nickName: '',
    avatarUrl: ''
  },
  async onLoad() {
    const res = await request('/user/info', {
      header: { token: wx.getStorageSync('token') }
    })
    if (res.code === 200) {
      this.setData({
        nickName: res.data.nickName,
        avatarUrl: res.data.avatarUrl
      })
    }
  }
})

第四步:用 button 和 input 收集头像、昵称 ​

为什么需要:新版小程序不能静默拿头像昵称,要让用户主动选择或填写。怎么想:头像用 button open-type="chooseAvatar",昵称用 input type="nickname"。怎么做:在 bindchooseavatar 回调里取 e.detail.avatarUrl,昵称可双向绑定或 bindinput 收集。易错点:chooseAvatar 拿到的是临时路径,后续要随更新接口提交;type="nickname" 在模拟器上可能不弹微信昵称,需真机验证;敏感昵称会被打码或拦截。

html
<button open-type="chooseAvatar" bindchooseavatar="onChooseAvatar">
  <image src="{{avatarUrl}}" />
</button>
<input type="nickname" model:value="{{nickName}}" />
js
onChooseAvatar(e) {
  this.setData({ avatarUrl: e.detail.avatarUrl })
}

第五步:更新资料后返回个人中心 ​

为什么需要:用户改完头像昵称要提交后台,并回到个人中心展示最新资料。怎么想:更新接口一般用 POST,请求体带昵称、头像,请求头带 token。怎么做:点击更新后调接口,成功后返回上一页。易错点:个人中心是 tabBar 页面时,不能用 navigateTo 或 redirectTo 跳过去;课堂使用的是 wx.navigateBack() 返回。另一个坑是个人中心 onLoad 只执行一次,返回时要用 onShow 重新获取用户信息。

js
async handleUpdate() {
  const res = await request('/user/update', {
    method: 'POST',
    header: { token: wx.getStorageSync('token') },
    data: {
      nickName: this.data.nickName,
      avatarUrl: this.data.avatarUrl
    }
  })
  if (res.code === 200) {
    wx.navigateBack()
  }
}
js
Page({
  onShow() {
    const token = wx.getStorageSync('token')
    if (token) this.getUserInfo()
  }
})

老版本写法的提醒 ​

课堂还补充了老版本 getUserInfo/getUserProfile 的写法:过去点按钮授权后可直接拿头像昵称,甚至不用发后台请求;后来规则调整,新版项目不能再用那套静默获取方式,只有较早上线的小程序可能还保留。易错点:不要把老代码直接抄到新项目;低版本、PC 端兼容性也可能不同;遇到“模拟器正常、真机头像不显示”,要优先怀疑微信缓存图或后台处理,不要只改前端 src。

先说明本节内容与标题的偏差 ​

本节笔记标题写作“六、搭建分类的静态?”,但转写稿实际讲的是微信小程序登录、授权、编辑用户信息与老版本授权写法,并未出现“分类静态页面”的图片或代码。为避免编造,下面按转写稿真实内容整理;转写稿只提到微信官方登录流程图,没有提供图片文件,因此不伪造图片链接,改用文字还原三方流程。

小程序登录为什么不能照搬普通前后台登录 ​

为什么需要:普通项目常见“注册—登录—拿 token”,但微信小程序运行在微信内,用户头像、昵称等身份资料来自微信,所以要先走微信授权流程。
怎么想:小程序不能自己凭空拿到微信用户身份,必须先通过 wx.login 拿临时凭证 code,再交给自己的后台去微信服务器换 openid/session_key。
怎么做:前端只负责拿 code、请求自己服务器、保存后台返回的自定义登录态 token。
易错点:code 是微信下发的临时凭证,不是最终 token;appID 和密钥属于管理员/后台配置,不能当前端公开常量乱用。

文字还原流程:小程序调用 wx.login 得到 code → 前端带 code 请求开发者服务器 → 开发者服务器带 appID、密钥、code 请求微信接口 → 微信返回 openid/session_key → 后台加密生成自定义登录态 → 前端持久化保存 token。

第一步:点击授权登录先拿 code ​

为什么需要:没有 code,后台无法向微信换取用户身份标识。
怎么想:授权按钮的点击回调里,先调 wx.login,成功后再发请求。
怎么做:按转写稿整理示意:

js
wx.login({
  success(res) {
    const code = res.code
    // 带着 code 请求自己的后台
    wx.request({
      url: '你的后台登录接口',
      data: { code },
      success(result) {
        if (result.data.code === 200) {
          wx.setStorageSync('token', result.data.token)
        }
      }
    })
  }
})

易错点:不要先弹授权再拿 code 的顺序混乱;不要以为前端能直接拿 openid;后台返回 token 后要判断成功再存储。

第二步:token 要持久化,并在请求头携带 ​

为什么需要:登录成功后,购物车、个人中心等业务请求都要证明“我是谁”。
怎么想:token 只在授权时拿一次,后续从本地缓存取,放到请求头里。
怎么做:转写稿中反复调试“请求头有没有带 token”。可整理为:

js
const token = wx.getStorageSync('token')
const header = {}
if (token) {
  header.token = token
}
wx.request({
  url: '业务接口地址',
  header
})

易错点:没 token 时不要硬塞空值;封装请求时要统一处理 header;token 存本地后,后续请求才能带上。转写稿还提醒:小程序本地存储有上限,PC 端常见上限与小程序不同,实际以文档为准。

第三步:编辑页先展示用户信息,再允许修改 ​

为什么需要:授权成功后进入编辑页,用户要先看到已有微信昵称、头像,再决定是否修改。
怎么想:进入编辑页先请求“获取用户信息”接口,接口要带 token;展示后再收集新昵称、新头像。
怎么做:转写稿中使用了 button open-type="chooseAvatar" 选择头像,input type="nickname" 获取微信昵称,并用双向绑定收集昵称。示意:

html
<button open-type="chooseAvatar" bindchooseavatar="onChooseAvatar">
  选择头像
</button>
<input type="nickname" model:value="{{nickName}}" />

易错点:头像地址可能是腾讯缓存地址,模拟器能显示、真机可能不显示;不要把头像 URL 当成永久可靠地址;昵称可改,但敏感内容会被处理。

第四步:更新成功后返回个人中心并刷新 ​

为什么需要:编辑页不是 tabBar 页面,更新成功后要回到个人中心,并让个人中心重新取用户信息。
怎么想:更新接口用 POST,请求体带昵称、头像;成功后用 wx.navigateBack 返回,而不是 navigateTo 跳 tabBar。
怎么做:

js
wx.request({
  url: '更新用户信息接口',
  method: 'POST',
  header: { token: wx.getStorageSync('token') },
  data: { nickName, avatarUrl },
  success(res) {
    if (res.data.code === 200) {
      wx.navigateBack()
    }
  }
})

易错点:wx.navigateTo 不能直接跳 tabBar;个人中心 onLoad 只执行一次,返回时未必重新请求,转写稿调试发现要在 onShow 等显示时机判断 token 后获取用户信息。

老版本写法的提醒 ​

转写稿还讲了 wx.getUserProfile 老版本授权:以前点按钮弹窗允许后可直接拿头像昵称,但现在新版本已废弃,低版本或早年上线的小程序才可能残留。易错点:不要在新项目照抄老写法;遇到“以前能拿、现在拿不到”,要查微信官方文档更新,而不是只怪代码。

课堂画面 ​

课堂画面 1

课堂画面 2

课堂画面 3

课堂画面 4

代码示例 ​

代码段一:网络请求二次封装(utils/request.js + api/index.js) ​

js
// utils/request.js —— 网络请求全部的页面使用,功能封装函数(复用)
// params: 调用函数传递参数 { url: 'xxx', method: 'post', data: { a: 1 } }
export default (params) => {
  return new Promise((resolve, reject) => {
    // 请求基础路径
    const baseURL = 'https://gmall-prod.atguigu.cn'

    // 发请求之前加载效果出来
    wx.showLoading({
      title: '加载....'
    })

    // 从本地存储取出 token(登录成功时存进去的)
    const token = wx.getStorageSync('token')

    // 请求头对象:没有 token 就是空对象,有 token 才加 token 字段
    let header = {}
    if (token) {
      header.token = token
    }

    // 发起网络请求
    wx.request({
      // 请求URL —— 绝对路径
      url: baseURL + params.url,
      // 请求方式
      method: params.method || 'GET',
      // 携带参数
      data: params.data || {},
      // 请求头携带 token
      header,
      // 成功回调,res 即为服务器响应数据
      success(res) {
        // 返回一个成功的 Promise 对象,简化数据
        resolve(res.data)
      },
      fail(error) {
        reject(error)
      },
      // 成功与失败钩子
      complete() {
        // 加载效果取消
        wx.hideLoading()
      }
    })
  })
}
js
// api/index.js —— 统一管理接口
import request from '../utils/request'

// 登录:携带 wx.login 拿到的 code,换取 token
export const reqLogin = (code) =>
  request({ url: '/api/user/weixin/wxLogin/' + code })

// 获取登录用户信息(请求头里已自动带上 token)
export const reqUserInfo = () =>
  request({ url: '/api/user/weixin/getUserInfo' })

// 更新用户信息
export const reqUpdateUserInfo = (data) =>
  request({
    url: '/api/user/weixin/updateUser',
    method: 'POST',
    data
  })

关键行与易错点

  • wx.hideLoading() 必须写在 complete 里,写在 success 里一旦请求失败 loading 就关不掉。
  • baseURL + params.url 是字符串拼接,params.url 必须以 / 开头,否则拼出来是 ...cnapixxx。
  • header 必须先声明成空对象再按需加 token,不能写成 header: { token: wx.getStorageSync('token') },否则没登录时也会带一个 token: '' 的空值。
  • resolve(res.data) 而不是 resolve(res),后面所有页面拿到的就是服务器数据本身,不用再 .data.data。
  • method: params.method || 'GET'、data: params.data || {} 是给参数兜底,不传也不会报错。

代码段二:登录页(wx.login 拿 code → 换 token → 存储 → 跳编辑页) ​

html
<!-- pages/login/login.wxml -->
<view class="login">
  <image class="logo" src="/images/logo.png"></image>
  <button type="primary" bindtap="handleLogin">微信授权登录</button>
</view>
js
// pages/login/login.js
import { reqLogin } from '../../api/index'

Page({
  // 点击授权登录按钮
  handleLogin() {
    // 1. 通过 wx.login 获取用户登录的临时凭证 code(微信下发的)
    wx.login({
      success: async (res) => {
        const { code } = res

        // 2. 携带 code 请求自己的服务器,换取 token
        const result = await reqLogin(code)

        // 3. 登录成功:本地持久化存储 token
        if (result.code === 200) {
          wx.setStorageSync('token', result.data.token)

          // 4. 跳转到编辑页,先把用户已有信息展示出来
          wx.navigateTo({ url: '/pages/edit/edit' })
        }
      }
    })
  }
})

关键行与易错点

  • code 是微信下发的临时凭证,不是 token;前端只做「发一个请求、拿到 token」这一件事,appId 和密钥是后端拿管理员的那一套去跟微信服务器换的。
  • wx.setStorageSync('token', ...) 必须做持久化存储,否则后面每个业务请求都拿不到登录态;本地存储上限是 1M。
  • 授权登录只需要做一次,所以这里用 navigateTo 跳到编辑页,登录页不会被销毁,后面更新完才能 navigateBack 回来。
  • wx.login 的 success 里用了 async/await,别忘了 success: async (res) => {} 的 async 关键字,否则 await 直接报语法错误。
  • result.code === 200 这个判断不能省,接口失败时 result.data.token 是 undefined,存进去等于没登录。

代码段三:编辑页(选头像、改昵称、更新)+ 个人中心回显 ​

html
<!-- pages/edit/edit.wxml -->
<view class="edit">
  <!-- button 的 open-type="chooseAvatar" 让用户选择微信头像 -->
  <button class="avatar-btn" open-type="chooseAvatar" bindchooseavatar="chooseAvatar">
    <image class="avatar" src="{{headImageUrl}}"></image>
  </button>

  <!-- type="nickname" 可以一键填入微信昵称,model:value 双向绑定 -->
  <input class="nickname" type="nickname" model:value="{{nickName}}" placeholder="请输入昵称" />

  <button type="primary" bindtap="handleUpdate">更新</button>
</view>
js
// pages/edit/edit.js
import { reqUserInfo, reqUpdateUserInfo } from '../../api/index'

Page({
  data: {
    nickName: '',
    headImageUrl: ''
  },

  onLoad() {
    this.getUserInfo()
  },

  // 获取用户信息并展示
  async getUserInfo() {
    const result = await reqUserInfo()
    if (result.code === 200) {
      this.setData({
        nickName: result.data.nickName,
        headImageUrl: result.data.headImageUrl
      })
    }
  },

  // 选择头像的回调(button open-type="chooseAvatar")
  chooseAvatar(e) {
    this.setData({ headImageUrl: e.detail.avatarUrl })
  },

  // 点击更新
  async handleUpdate() {
    const { nickName, headImageUrl } = this.data
    const result = await reqUpdateUserInfo({ nickName, headImageUrl })

    if (result.code === 200) {
      // 返回个人中心:tabBar 页面不能用 navigateTo / redirectTo
      wx.navigateBack()
    }
  }
})
html
<!-- pages/mine/mine.wxml -->
<view class="mine">
  <image class="avatar" src="{{headImageUrl || '/images/default.png'}}"></image>
  <text>{{nickName || '微信用户'}}</text>
  <button bindtap="goEdit">编辑个人中心</button>
</view>
js
// pages/mine/mine.js
import { reqUserInfo } from '../../api/index'

Page({
  data: {
    nickName: '',
    headImageUrl: ''
  },

  // 用 onShow:从编辑页返回时要重新拉一次用户信息
  onShow() {
    const token = wx.getStorageSync('token')
    // 有 token 才说明授权登录过,才去请求用户信息
    if (token) {
      this.getUserInfo()
    }
  },

  async getUserInfo() {
    const result = await reqUserInfo()
    if (result.code === 200) {
      this.setData({
        nickName: result.data.nickName,
        headImageUrl: result.data.headImageUrl
      })
    }
  },

  // 从 tabBar 页跳到非 tabBar 页,用 navigateTo
  goEdit() {
    wx.navigateTo({ url: '/pages/edit/edit' })
  }
})

关键行与易错点

  • open-type="chooseAvatar" + bindchooseavatar 是取头像的正规写法,回调里从 e.detail.avatarUrl 取地址;input type="nickname" 是取微信昵称的正规写法,两者取到后都要自己收集再发请求更新。
  • 更新成功后不能用 wx.navigateTo / wx.redirectTo 回个人中心,因为个人中心是 tabBar 页面;这里用 wx.navigateBack()(也可以用 wx.switchTab),前提是登录页当时用的是 navigateTo,登录页还在栈里没被销毁。
  • 个人中心必须用 onShow 而不是 onLoad:onLoad 一个页面只执行一次,从编辑页 navigateBack 回来不会重新触发,数据就是旧的。
  • onShow 里先 wx.getStorageSync('token') 判断,没授权过就发请求是没有意义的。
  • 真机上微信头像地址是腾讯的缓存域名,可能出现「名字能显示、头像显示不出来」的情况,这属于已知现象,不是代码写错。

常见错误 ​

  1. 页面里拿到的数据总要多剥一层(res.data.data) 现象:封装层 resolve(res),业务页拿到的是整个响应对象,字段全对不上。 原因:wx.request 的 success 回调里 res 是响应包装对象,业务数据在 res.data。 修法:封装层统一 resolve(res.data),页面只处理业务数据;若后端还包一层 {code,data,msg},在封装层一次剥干净,别让每个页面各剥各的。

  2. 请求失败时 loading 永远转圈 现象:网络断开或接口 500,页面卡在“加载中”,只能杀进程。 原因:wx.hideLoading() 只写在 success 里,fail 分支不执行。 修法:收尾动作放 complete,成功失败都关;更稳的做法是 fail 里先 wx.showToast 再走 complete 关 loading。

  3. token 存了,但业务请求仍然提示未登录 现象:登录成功、wx.setStorageSync('token', ...) 也执行了,取用户信息接口依旧 401。 原因:封装函数里 header 写死成空对象,或取 token 的 key 与存的 key 不一致,或 header 拼在 data 里。 修法:在封装函数内部统一取本地 token 拼 header(有 token 才加该字段),业务层不再各自拼;key 抽成常量,存取同一处引用。

  4. 未登录就进页面发请求,报错或空数据 现象:首次进入个人中心,接口直接抛错,控制台一片红。 原因:onLoad 里无条件调 getUserInfo,此时本地还没有 token。 修法:先 wx.getStorageSync('token') 判空,有 token 才发请求;无 token 走未登录 UI,不要靠接口报错来兜底。

  5. 更新成功后跳不回个人中心 现象:编辑页点“更新”,wx.navigateTo / redirectTo 到个人中心无效或白屏。 原因:目标页是 tabBar 页,这两个 API 都不支持跳 tabBar。 修法:从登录/编辑这类非 tabBar 页返回,用 wx.navigateBack();确实要切 tabBar 用 wx.switchTab()。同时检查登录页是用 navigateTo 进的(页面栈还在),否则 navigateBack 无处可回。

  6. 返回个人中心后头像昵称还是旧的 现象:编辑页改了昵称,返回后页面显示未变,手动下拉刷新才对。 原因:onLoad 只在首次加载执行一次,返回时不触发。 修法:把取用户信息的逻辑放 onShow(或 onShow 里判断是否需要刷新),onLoad 只做一次性初始化。

  7. 照着老教程写 open-type="getUserInfo" / wx.getUserInfo 拿不到头像昵称 现象:授权弹窗不出现,或返回的 userInfo 是匿名数据(灰色头像、“微信用户”)。 原因:该能力已被官方回收,新版本基础库不再返回真实头像昵称。 修法:改用 button open-type="chooseAvatar" 取头像、input type="nickname" 取昵称,收集后随更新接口提交;遇到只在小程序里能跑的旧写法,先查基础库版本与官方公告。

  8. 模拟器头像正常、真机不显示 现象:开发者工具里图片好好的,真机一片空白。 原因:微信返回的是腾讯侧缓存域名下的临时头像地址,真机环境下存在限制/失效。 修法:<image> 加 binderror 兜底切本地占位图;根治要靠后端把头像转存到自家域名后再下发。

练习 ​

  1. 现有封装函数只 resolve(res.data),没有任何错误提示。请改造:让 fail 时页面能拿到可读的错误信息(提示 + reject 一个带 message 的对象),并保证 loading 一定关闭。写出改造后的关键代码段。

  2. 写一个 request 的调用方示例:页面 A 需要“登录后才能拿到”的用户信息,要求包含 token 判空、调用、成功赋值、失败提示四步,不允许在页面里手写 header。

  3. 梳理页面栈:登录页 →(授权成功)→ 编辑页 →(更新成功)→ 个人中心(tabBar)。分别说明每一步该用 navigateTo / navigateBack / switchTab 中的哪一个,并说明若第一步误用 redirectTo 会在哪一步出问题。

  4. 个人中心页要求:首次进入有 token 就展示用户信息,从编辑页返回后要展示最新信息,无 token 展示“未登录”。请给出 onLoad / onShow 的职责划分方案(只写结构与判断逻辑,不写完整代码)。

  5. 排查题:同事反馈“编辑页改了昵称,接口返回 200,但个人中心没变化,且控制台无报错”。请列出至少三条可能原因及对应的验证方式。

原视频对照 ​

#视频时长
1微信小程序登录的流程32:11
2微信小程序编辑模块业务27:33
3微信小程序完成用户授权登录业务28:01
4微信小程序用户授权老版本写法24:32

小结 ​

  1. 封装的价值不在少写几行 wx.request,而在把 loading、header、数据剥离、错误处理收敛到一处;任何一处散落到页面,迟早会漏。
  2. complete 是收尾动作的唯一可靠位置,success/fail 只负责分支业务,不负责清理。
  3. token 的“存”和“带”必须成对设计:存的时候想清楚 key,带的时候统一在封装层拼,页面不该知道 header 长什么样。
  4. 登录态判断要前置到发请求之前,用本地存储做门禁,而不是靠接口报错来告诉你“没登录”。
  5. 小程序页面栈是有记忆的:navigateBack 能否生效取决于来路,tabBar 页只能 switchTab,跳转 API 选错的表现往往是“没反应”而非报错。
  6. onLoad 一次、onShow 每次,凡是“返回后要变”的数据都该放 onShow,这是列表页、个人中心页的通用规律。
  7. 微信开放能力会回收:老写法能跑不代表能上线,遇到“文档说可以、实际拿不到”,先查基础库版本和官方公告,再决定改方案。
  8. 模拟器通过不等于交付通过,头像、授权、type="nickname" 这类强依赖客户端的能力,必须真机验证一次。