目录
- 1. 基本知识
- 2. Demo
- 3. 拓展
1. 基本知识
从实战代码中学习,上述实战代码来源:芋道源码/yudao-mall-uniapp
该代码中,通过自定义 request 函数对 HTTP 请求进行了统一管理,并且结合了 Token 认证机制
- 动态设置请求头:根据 config 的配置,决定是否需要在请求头中附加 Authorization(Bearer Token)。Token 是从本地存储中获取的
- 根据环境区分不同的 Base URL:根据当前的开发环境(development 或 production),动态设置请求的基础 URL(baseUrl)
- 统一处理请求参数:config.params 会被转化成查询字符串,拼接到请求的 URL 后面
- Promise 封装异步操作:请求通过 uni.request 发出,并将返回的 response 数据封装为一个 Promise,使得调用 request 的地方可以使用 then 或 catch 来处理结果
- Token 认证管理原理
- Token 存储:uni.setStorageSync 和 uni.getStorageSync 被用来在客户端本地存储 ACCESS_TOKEN 和 REFRESH_TOKEN,这两个 Token 被用于身份验证
- 获取 Token:在每次 HTTP 请求时,首先会检查请求是否需要 Token(通过 config.headers.isToken 判断)。如果需要,就从本地存储中获取 AccessToken 并加入到请求头中
- Token 过期处理:当请求返回的状态码为 401 时,表示 Token 已过期,此时会弹出提示框,让用户重新登录并清除旧的 Token
- 错误处理机制
- 网络错误:封装了常见的网络错误(如超时、服务器错误等),并提供了友好的提示
- 接口返回错误:统一处理接口返回的错误,错误信息根据 res.data.code 的值来决定,如果返回的是 500 错误或其他非 200 的错误,则通过 toast 提示给用户
- 401 错误处理:当返回状态码为 401 时,表示 Token 过期或无效,代码会自动处理登出流程
2. Demo
根据实战中的Demo,给出一版通用的Demo:
js">token comment">// utils/request.js
token keyword">import token punctuation">{ getAccessTokentoken punctuation">, setTokentoken punctuation">, removeToken token punctuation">} token keyword">from token string">'@/utils/auth'token punctuation">;
token keyword">import config token keyword">from token string">'@/config'token punctuation">;
token keyword">import errorCode token keyword">from token string">'@/utils/errorCode'token punctuation">;
token keyword">import token punctuation">{ toasttoken punctuation">, showConfirm token punctuation">} token keyword">from token string">'@/utils/common'token punctuation">;token keyword">let timeout token operator">= token number">10000token punctuation">;
token keyword">let baseUrl token operator">= processtoken punctuation">.envtoken punctuation">.token constant">NODE_ENV token operator">=== token string">'development' token operator">? configtoken punctuation">.devbaseUrl token operator">: configtoken punctuation">.prodbaseUrltoken punctuation">;token keyword">const token function-variable function">request token operator">= token parameter">config token operator">=> token punctuation">{token keyword">const isToken token operator">= token punctuation">(configtoken punctuation">.headers token operator">|| token punctuation">{token punctuation">}token punctuation">)token punctuation">.isToken token operator">=== token boolean">falsetoken punctuation">;configtoken punctuation">.header token operator">= configtoken punctuation">.header token operator">|| token punctuation">{token punctuation">}token punctuation">;token keyword">if token punctuation">(token function">getAccessTokentoken punctuation">(token punctuation">) token operator">&& token operator">!isTokentoken punctuation">) token punctuation">{configtoken punctuation">.headertoken punctuation">[token string">'Authorization'token punctuation">] token operator">= token string">'Bearer ' token operator">+ token function">getAccessTokentoken punctuation">(token punctuation">)token punctuation">;token punctuation">}configtoken punctuation">.headertoken punctuation">[token string">'tenant-id'token punctuation">] token operator">= token string">'1'token punctuation">; token comment">// 强制设置租户 IDtoken keyword">if token punctuation">(configtoken punctuation">.paramstoken punctuation">) token punctuation">{token keyword">let url token operator">= configtoken punctuation">.url token operator">+ token string">'?' token operator">+ token function">tansParamstoken punctuation">(configtoken punctuation">.paramstoken punctuation">)token punctuation">;url token operator">= urltoken punctuation">.token function">slicetoken punctuation">(token number">0token punctuation">, token operator">-token number">1token punctuation">)token punctuation">;configtoken punctuation">.url token operator">= urltoken punctuation">;token punctuation">}token keyword">return token keyword">new token class-name">Promisetoken punctuation">(token punctuation">(token parameter">resolvetoken punctuation">, rejecttoken punctuation">) token operator">=> token punctuation">{unitoken punctuation">.token function">requesttoken punctuation">(token punctuation">{token literal-property property">methodtoken operator">: configtoken punctuation">.method token operator">|| token string">'get'token punctuation">,token literal-property property">timeouttoken operator">: configtoken punctuation">.timeout token operator">|| timeouttoken punctuation">,token literal-property property">urltoken operator">: configtoken punctuation">.baseUrl token operator">|| baseUrl token operator">+ configtoken punctuation">.urltoken punctuation">,token literal-property property">datatoken operator">: configtoken punctuation">.datatoken punctuation">,token literal-property property">headertoken operator">: configtoken punctuation">.headertoken punctuation">,token literal-property property">dataTypetoken operator">: token string">'json'token punctuation">}token punctuation">)token punctuation">.token function">thentoken punctuation">(token parameter">response token operator">=> token punctuation">{token keyword">let token punctuation">[errortoken punctuation">, restoken punctuation">] token operator">= responsetoken punctuation">;token keyword">if token punctuation">(errortoken punctuation">) token punctuation">{token function">toasttoken punctuation">(token string">'后端接口连接异常'token punctuation">)token punctuation">;token function">rejecttoken punctuation">(token string">'后端接口连接异常'token punctuation">)token punctuation">;token keyword">returntoken punctuation">;token punctuation">}token keyword">const code token operator">= restoken punctuation">.datatoken punctuation">.code token operator">|| token number">200token punctuation">;token keyword">const msg token operator">= errorCodetoken punctuation">[codetoken punctuation">] token operator">|| restoken punctuation">.datatoken punctuation">.msg token operator">|| errorCodetoken punctuation">[token string">'default'token punctuation">]token punctuation">;token keyword">if token punctuation">(code token operator">=== token number">401token punctuation">) token punctuation">{token function">showConfirmtoken punctuation">(token string">'登录状态已过期,您可以继续留在该页面,或者重新登录?'token punctuation">)token punctuation">.token function">thentoken punctuation">(token parameter">res token operator">=> token punctuation">{token keyword">if token punctuation">(restoken punctuation">.confirmtoken punctuation">) token punctuation">{token function">removeTokentoken punctuation">(token punctuation">)token punctuation">;unitoken punctuation">.token function">reLaunchtoken punctuation">(token punctuation">{ token literal-property property">urltoken operator">: token string">'/pages/login' token punctuation">}token punctuation">)token punctuation">;token punctuation">}token punctuation">}token punctuation">)token punctuation">;token function">rejecttoken punctuation">(token string">'无效的会话,或者会话已过期,请重新登录。'token punctuation">)token punctuation">;token punctuation">} token keyword">else token keyword">if token punctuation">(code token operator">=== token number">500token punctuation">) token punctuation">{token function">toasttoken punctuation">(msgtoken punctuation">)token punctuation">;token function">rejecttoken punctuation">(token string">'500'token punctuation">)token punctuation">;token punctuation">} token keyword">else token keyword">if token punctuation">(code token operator">!== token number">200token punctuation">) token punctuation">{token function">toasttoken punctuation">(msgtoken punctuation">)token punctuation">;token function">rejecttoken punctuation">(codetoken punctuation">)token punctuation">;token punctuation">}token function">resolvetoken punctuation">(restoken punctuation">.datatoken punctuation">)token punctuation">;token punctuation">}token punctuation">)token punctuation">.token function">catchtoken punctuation">(token parameter">error token operator">=> token punctuation">{token keyword">let token punctuation">{ message token punctuation">} token operator">= errortoken punctuation">;token keyword">if token punctuation">(message token operator">=== token string">'Network Error'token punctuation">) message token operator">= token string">'后端接口连接异常'token punctuation">;token keyword">else token keyword">if token punctuation">(messagetoken punctuation">.token function">includestoken punctuation">(token string">'timeout'token punctuation">)token punctuation">) message token operator">= token string">'系统接口请求超时'token punctuation">;token keyword">else token keyword">if token punctuation">(messagetoken punctuation">.token function">includestoken punctuation">(token string">'Request failed with status code'token punctuation">)token punctuation">) message token operator">= token string">'系统接口' token operator">+ messagetoken punctuation">.token function">substrtoken punctuation">(messagetoken punctuation">.length token operator">- token number">3token punctuation">) token operator">+ token string">'异常'token punctuation">;token function">toasttoken punctuation">(messagetoken punctuation">)token punctuation">;token function">rejecttoken punctuation">(errortoken punctuation">)token punctuation">;token punctuation">}token punctuation">)token punctuation">;token punctuation">}token punctuation">)token punctuation">;
token punctuation">}token punctuation">;token keyword">export token keyword">default requesttoken punctuation">;
对应的token文件:
js">token comment">// utils/auth.js
token keyword">const AccessTokenKey token operator">= token string">'ACCESS_TOKEN'token punctuation">;
token keyword">const RefreshTokenKey token operator">= token string">'REFRESH_TOKEN'token punctuation">;token keyword">export token keyword">function token function">getAccessTokentoken punctuation">(token punctuation">) token punctuation">{token keyword">return unitoken punctuation">.token function">getStorageSynctoken punctuation">(AccessTokenKeytoken punctuation">)token punctuation">;
token punctuation">}token keyword">export token keyword">function token function">getRefreshTokentoken punctuation">(token punctuation">) token punctuation">{token keyword">return unitoken punctuation">.token function">getStorageSynctoken punctuation">(RefreshTokenKeytoken punctuation">)token punctuation">;
token punctuation">}token keyword">export token keyword">function token function">setTokentoken punctuation">(token parameter">tokentoken punctuation">) token punctuation">{unitoken punctuation">.token function">setStorageSynctoken punctuation">(AccessTokenKeytoken punctuation">, tokentoken punctuation">.accessTokentoken punctuation">)token punctuation">;unitoken punctuation">.token function">setStorageSynctoken punctuation">(RefreshTokenKeytoken punctuation">, tokentoken punctuation">.refreshTokentoken punctuation">)token punctuation">;
token punctuation">}token keyword">export token keyword">function token function">removeTokentoken punctuation">(token punctuation">) token punctuation">{unitoken punctuation">.token function">removeStorageSynctoken punctuation">(AccessTokenKeytoken punctuation">)token punctuation">;unitoken punctuation">.token function">removeStorageSynctoken punctuation">(RefreshTokenKeytoken punctuation">)token punctuation">;
token punctuation">}
相关接口请求:
js">token comment">// 在页面中调用封装的请求方法
token keyword">import request token keyword">from token string">'@/utils/request'token punctuation">;token keyword">export token keyword">default token punctuation">{token literal-property property">methodstoken operator">: token punctuation">{token function">fetchDatatoken punctuation">(token punctuation">) token punctuation">{token function">requesttoken punctuation">(token punctuation">{token literal-property property">urltoken operator">: token string">'/api/getData'token punctuation">,token literal-property property">methodtoken operator">: token string">'GET'token punctuation">,token literal-property property">paramstoken operator">: token punctuation">{ token literal-property property">idtoken operator">: token number">123 token punctuation">}token punctuation">}token punctuation">)token punctuation">.token function">thentoken punctuation">(token parameter">response token operator">=> token punctuation">{consoletoken punctuation">.token function">logtoken punctuation">(token string">'数据:'token punctuation">, responsetoken punctuation">)token punctuation">;token punctuation">}token punctuation">)token punctuation">.token function">catchtoken punctuation">(token parameter">error token operator">=> token punctuation">{consoletoken punctuation">.token function">logtoken punctuation">(token string">'请求失败:'token punctuation">, errortoken punctuation">)token punctuation">;token punctuation">}token punctuation">)token punctuation">;token punctuation">}token punctuation">}
token punctuation">}
3. 拓展
process.env.NODE_ENV
是 Node.js 环境中用于获取当前应用运行环境的一个变量
在大多数前端框架(如 Vue、React)以及后端框架(如 Express)中,process.env.NODE_ENV 被广泛用于区分不同的开发环境
前端vue中可能已经标明了
在开发模式下:NODE_ENV=development npm run dev
在生产模式下:NODE_ENV=production npm run build
在 npm 脚本中,可以通过 cross-env 等工具来跨平台设置环境变量:
token string">"scripts"token operator">: token punctuation">{token string">"dev"token operator">: token string">"cross-env NODE_ENV=development vue-cli-service serve"token punctuation">,token string">"build"token operator">: token string">"cross-env NODE_ENV=production vue-cli-service build"
token punctuation">}
另外一个接口超时时间,全局默认是20秒,如果时长不对,可以在单独某个接口设置:
js">token comment">// 上传图片
token function">uploadImagetoken punctuation">(token parameter">datatoken punctuation">) token punctuation">{token keyword">return token function">uploadtoken punctuation">(token punctuation">{token literal-property property">urltoken operator">: token string">'/infra/file/upload'token punctuation">,token literal-property property">methodtoken operator">: token string">'upload'token punctuation">,token literal-property property">filePathtoken operator">: datatoken punctuation">.filePathtoken punctuation">,token literal-property property">timeouttoken operator">: token number">30000 token comment">// 设置超时时间为30秒token punctuation">}token punctuation">)token punctuation">;
token punctuation">}