请求封装前言
-
通常在小程序项目中,微信已经提供了网络请求API,但是往往这点并不能满足我们,所以有了下面的封装
-
Requset请求往往我们有很多需求,此处简单罗列需求并代码实现
- 根据不同版本小程序
develop --> trial --> release
版本使用不同域名 - request 拦截器,对当前请求发送前做相应处理
- 可控式请求 loading 动画,同时支持扩展自定义 loading 文字提示
- 根据后端返回请求响应结果做相应处理(列如 210 未登录,220 登录失效等需要与后端共同定义)
- 根据不同版本小程序
- 笔者使用的是
Taro
进行请求封装,解释步骤基本在代码中有描述,笔者没有对每个方法拆分详细讲述 - 笔者是根据之前分享的是Taro模板中的请求封装,拆分讲述思路,可供参考借鉴
- 前言废话太多下面上代码
开始
- 首先在项目
pages
平级创建service
文件夹,然后分别建立3个文件分别是:interceptors.ts
– 请求响应拦截器。
import Taro from '@tarojs/taro' import { HTTP_STATUS } from './status' // 笔者这里引入 mobx 是对 未登录,登陆失效 等做处理 import cartStroe from '../store/user'
const customInterceptor = (chain:any) => {
<span class="hljs-keyword">const</span> requestParams = chain.requestParams <span class="hljs-keyword">return</span> chain.proceed(requestParams).then(<span class="hljs-function">(<span class="hljs-params">res:any</span>) =></span> { <span class="hljs-comment">// 清除 loading</span> <span class="hljs-keyword">if</span>(requestParams.loading) Taro.hideLoading() <span class="hljs-keyword">switch</span>(res.statusCode) { <span class="hljs-keyword">case</span> HTTP_STATUS.SUCCESS: <span class="hljs-keyword">const</span> result = res.data <span class="hljs-keyword">if</span>(res.data.code === <span class="hljs-number">200</span>) { <span class="hljs-comment">// 接口调通且无异常赋予success标识</span> result.success = <span class="hljs-literal">true</span> } <span class="hljs-keyword">else</span> { <span class="hljs-comment">// 请求接口错误提示,可通过参数中加入 openErrTips: false 关闭</span> <span class="hljs-keyword">if</span>(requestParams.openErrTips && result.msg) Taro.showToast({ <span class="hljs-attr">title</span>: result.msg, <span class="hljs-attr">icon</span>: <span class="hljs-string">'none'</span> }) <span class="hljs-comment">// 登录过期或未登录 需要与后端共同定义</span> <span class="hljs-keyword">if</span>(result.code === <span class="hljs-number">210</span> || result.code === <span class="hljs-number">220</span>) { <span class="hljs-comment">// 跳转登陆 清空用户信息等 处理</span> cartStroe.setStatus(<span class="hljs-literal">false</span>) cartStroe.setUser({}) Taro.showToast({ <span class="hljs-attr">title</span>: (result.code === <span class="hljs-number">210</span> ? <span class="hljs-string">'未登录,请先登陆'</span> : <span class="hljs-string">'登录信息失效,请重新登陆'</span> ), <span class="hljs-attr">icon</span>: <span class="hljs-string">'none'</span> }) Taro.navigateTo({ <span class="hljs-attr">url</span>: <span class="hljs-string">'/pages/login/index'</span> }) <span class="hljs-keyword">return</span> <span class="hljs-built_in">Promise</span>.reject(result) } } <span class="hljs-keyword">return</span> result <span class="hljs-keyword">case</span> HTTP_STATUS.CREATED: <span class="hljs-keyword">return</span> <span class="hljs-built_in">Promise</span>.reject(<span class="hljs-string">'请求成功并且服务器创建了新的资源'</span>) <span class="hljs-keyword">case</span> HTTP_STATUS.ACCEPTED: <span class="hljs-keyword">return</span> <span class="hljs-built_in">Promise</span>.reject(<span class="hljs-string">'接受请求但没创建资源'</span>) <span class="hljs-keyword">case</span> HTTP_STATUS.CLIENT_ERROR: <span class="hljs-keyword">return</span> <span class="hljs-built_in">Promise</span>.reject(<span class="hljs-string">'服务器不理解请求的语法'</span>) <span class="hljs-keyword">case</span> HTTP_STATUS.AUTHENTICATE: <span class="hljs-keyword">return</span> <span class="hljs-built_in">Promise</span>.reject(<span class="hljs-string">'请求要求身份验证。 对于需要登录的网页,服务器可能返回此响应'</span>) <span class="hljs-keyword">case</span> HTTP_STATUS.FORBIDDEN: <span class="hljs-keyword">return</span> <span class="hljs-built_in">Promise</span>.reject(<span class="hljs-string">'服务器拒绝请求'</span>) <span class="hljs-keyword">case</span> HTTP_STATUS.NOT_FOUND: <span class="hljs-keyword">return</span> <span class="hljs-built_in">Promise</span>.reject(<span class="hljs-string">'服务器找不到请求的网页'</span>) <span class="hljs-keyword">case</span> HTTP_STATUS.SERVER_ERROR: <span class="hljs-keyword">return</span> <span class="hljs-built_in">Promise</span>.reject(<span class="hljs-string">'(服务器内部错误) 服务器遇到错误,无法完成请求'</span>) <span class="hljs-keyword">case</span> HTTP_STATUS.BAD_GATEWAY: <span class="hljs-keyword">return</span> <span class="hljs-built_in">Promise</span>.reject(<span class="hljs-string">'(错误网关) 服务器作为网关或代理,从上游服务器收到无效响应'</span>) <span class="hljs-keyword">case</span> HTTP_STATUS.SERVICE_UNAVAILABLE: <span class="hljs-keyword">return</span> <span class="hljs-built_in">Promise</span>.reject(<span class="hljs-string">'(服务不可用) 服务器目前无法使用(由于超载或停机维护)。 通常,这只是暂时状态。'</span>) <span class="hljs-keyword">case</span> HTTP_STATUS.GATEWAY_TIMEOUT: <span class="hljs-keyword">return</span> <span class="hljs-built_in">Promise</span>.reject(<span class="hljs-string">'(网关超时) 服务器作为网关或代理,但是没有及时从上游服务器收到请求'</span>) <span class="hljs-attr">default</span>: <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'请开发者检查请求拦截未匹配到错误,返回statusCode :>> '</span>, res.statusCode) <span class="hljs-keyword">break</span> } })
}
// Taro 提供了两个内置拦截器 // logInterceptor - 用于打印请求的相关信息 // timeoutInterceptor - 在请求超时时抛出错误。 const interceptors = [customInterceptor, Taro.interceptors.logInterceptor]
export default interceptors
status.ts
– HTTP 通用响应状态码提示(方便开发者寻找请求错误源)。
export const HTTP_STATUS = { // 成功处理了请求,一般情况下都是返回此状态码 SUCCESS: 200, // 请求成功并且服务器创建了新的资源 CREATED: 201, // 接受请求但没创建资源 ACCEPTED: 202, // 服务器不理解请求的语法 CLIENT_ERROR: 400, // 请求要求身份验证。 对于需要登录的网页,服务器可能返回此响应 AUTHENTICATE: 401, // 服务器拒绝请求 FORBIDDEN: 403, // 服务器找不到请求的网页 NOT_FOUND: 404, // (服务器内部错误) 服务器遇到错误,无法完成请求 SERVER_ERROR: 500, // (错误网关) 服务器作为网关或代理,从上游服务器收到无效响应 BAD_GATEWAY: 502, // (服务不可用) 服务器目前无法使用(由于超载或停机维护)。 通常,这只是暂时状态。 SERVICE_UNAVAILABLE: 503, // (网关超时) 服务器作为网关或代理,但是没有及时从上游服务器收到请求 GATEWAY_TIMEOUT: 504 }
/**
- 此处有替补实现方式
- 使用键值对直接通过状态码取值
- const HTTP_STATUS = {
- ‘200’: ‘请求服务器端成功’,
- ‘201’: ‘’
- }
- if(HTTP_STATUS[res.statusCode])
- console.log(HTTP_STATUS[res.statusCode])
- else
- console.log(
请开发者检查请求拦截未匹配到错误,返回statusCode :>> ${res.statusCode}
) */
index.ts
– 封装请求导出供调用。
import Taro from '@tarojs/taro'
import interceptors from ‘./interceptors’
interceptors.forEach(interceptorItem => Taro.addInterceptor(interceptorItem))
// 模块,命名空间,基础接口声明,此处不作解释 自行了解,结尾提供文档指引
declare namespace RequestProps {
interface Method {
‘GET’,
‘POST’,
‘PUT’,
‘DELETE’
}
interface Options {
url: string,
method: keyof Method,
data: any,
loading?: boolean,
loadingTitle?: string,
contentType?: string,
openErrTips?: boolean
}
interface requestParams {
url: string,
method: keyof Method,
data: any,
header: any,
loading?: boolean,
loadingTitle?: string,
contentType?: string,
openErrTips?: boolean
}
}
/**
-
获取版本 retrun 对应环境域名
-
develop: ‘开发版’, trial: ‘体验版’, release: ‘正式版’
-
支持扩展 - 思路 可通过 process.env.NODE_ENV 判断当前打包是 生产模式或工厂模式 进而判断 适合多环境 dev -> beta -> uat -> pro
-
@returns 域名
*/
const getVersion = () => {
// @ts-ignore
switch (__wxConfig.envVersion)
{
case ‘develop’:
return ‘http://develop.gavinpeng.club’
case ‘trial’:
return ‘http://trial.gavinpeng.club’
case ‘release’:
return ‘http://release.gavinpeng.club’
default:
return ‘http://develop.gavinpeng.club’
}
}
class Request {
baseOptions(options: RequestProps.Options) {
let { url, method, data } = options
// 过滤 扩展属性
let { loading, loadingTitle, contentType, openErrTips, …rest } = data
<span class="hljs-keyword">if</span>(loading) Taro.showLoading({ <span class="hljs-attr">title</span>: loadingTitle || <span class="hljs-string">'加载中...'</span>, <span class="hljs-attr">mask</span>: <span class="hljs-literal">true</span> })
<span class="hljs-keyword">const</span> requestParams: RequestProps.requestParams = {
<span class="hljs-attr">url</span>: getVersion() + url,
method,
<span class="hljs-attr">data</span>: rest,
<span class="hljs-attr">header</span>: {
<span class="hljs-comment">// 支持自定义 contentType</span>
<span class="hljs-string">'content-type'</span>: contentType || <span class="hljs-string">'application/json'</span>,
<span class="hljs-comment">// Token</span>
<span class="hljs-string">'Authorization'</span>: Taro.getStorageSync(<span class="hljs-string">'token'</span>)
<span class="hljs-comment">// 此处支持扩展,可通过请求 data 参数中加入 header 对象,在上面过滤 语法糖 ...header 此处就不做过多解释,需要的自行添加了解</span>
<span class="hljs-comment">// ...header</span>
},
<span class="hljs-comment">// 请求是否带 loading, 传递到 请求响应拦截器 清除 loading </span>
loading,
openErrTips
}
<span class="hljs-keyword">return</span> Taro.request(requestParams)
}
<span class="hljs-keyword">get</span>(url:string, data:any) {
<span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.baseOptions({ url, <span class="hljs-attr">method</span>:<span class="hljs-string">'GET'</span>, data })
}
post(url:string, <span class="hljs-attr">data</span>:any) {
<span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.baseOptions({ url, <span class="hljs-attr">method</span>:<span class="hljs-string">'POST'</span>, data })
}
}
export default new Request()
- 在项目
pages
平级创建api
文件夹(统一管理接口) - 在
api
建立index.ts
(导出接口)
import * as test from './test'
const Api = {
// 测试模块
…test,
// xxx 模块
}
// 导出所有接口
export default Api
- 在
api
建立测试模块接口列表test.ts
/*
* @Author: Gavin
* @CreateTime: xxxx
* @Describe: 测试模块相关接口
*/
// 引入封装后的请求方法
import request from '@/service/index'
/**
- 测试
- @param params
- @returns
*/
export const isTest = (url:string, data:any) => {
return request.post(url, data)
}
- 在
page
页面引入接口import Api from '@/api/index'
并使用接口
Api.isTest({
id: 1,
name: 'Gavin',
// 扩展参数 - 是否需要 loading 非必传默认:false
loading: true,
// 扩展参数 - 是否自定义 loadingTitle 非必传默认:加载中...(注:没有开启 loading 此参数无效)
loadingTitle: '自定义加载提示',
// 扩展参数 - 是否自定义 contentType 非必传默认:application/json
contentType: 'x-www-form-urlencoded',
// 扩展参数 - 是否需要请求错误提示 openErrTips 非必传默认:false
openErrTips: true,
// 扩展参数 - 上面讲到的 自定义 header 需要的在封装中添加
// header: { }
}).then((res:any) => {
// 成功
}).catch((err:any) => {
// 失败
})
结尾
- 讲述过程中如有不对或错地方还请指出,欢迎各路大佬们指教
- 每一次分享是为了进步,在此过程中,讲述代码思路,亦可以很好的锻炼自身的表达能力
- 成长是生活的动力,加油吧
新生代农民工
们!
TypeScript 中文文档指引
请求封装陈述源码地址