n-request #

简洁干脆的请求器。颗粒细,可配置和定制能力强。有任何问题可以加我QQ:382006503或者微信:pptpdf

整个处理逻辑都比较直接,代码也比较直白,就是简单粗暴的去适配uni.request,并且支持全局配置独立覆盖

  • 请求拦截,比如Header/URL配置检测、自动刷新Token等;
  • 响应拦截;
  • uni.request的回调中使用的全局callback;
  • api级别的callback;
  • 支持常规请求,上传以及下载;
  • 支持Promise以及Task;
  • 支持同步/异步;
  • 更多...

注意:

没有对header做细致的合并工作(不打算处理),也就是请求中的header配置是直接覆盖全局中的header配置,而不是差异合并(当然,如果你有特殊需求,可以在请求拦截器里面处理header)。

不对url进行任何的检测(自己保证url的合法性),最终的url就是baseUrlapi配置中url的拼接(当然,你可以在拦截请求器里面修改url)。

可以根据需要在构建接口时任意添加参数/字段,方便你在拦截器里面使用。

请求被拦截也会进入响应拦截器里面,而且会自动reject返回的内容,响应拦截器接收到的数据为{nCancel:true, response:...}

请求fail也会进入响应拦截器里面,而且会自动reject返回的内容,fail时响应拦截器接收到的数据为{nFail:true, response:...}

success/fail/complete回掉并不对应uni.request,而是对应响应拦截器的处理逻辑,resolve对应successreject对应fail

不会类axios处理,不会进一步抽象与提炼。

使用 #

源码比较直白,可以看源码:

  • Requestclass对象,需要实例化;
  • 提供了一个request方法,request方法会调用您设置的请求拦截器,提前拦截;
  • 适配uni.request,完成 request 方法;
  • 请求取消或者失败会走rejectcatch中处理);
  • 您可以通过nReqToReject在响应拦截器中自由控制是否进入reject
  • fail情况下也会进入响应拦截器,是否fail根据response中的nFail来做判断;
  • 请求被拦截也会进入响应拦截器,是否被拦截根据response中的nCancel来做判断;

初始化请求器 #

自己可以新建一个 request.js,用来配置自己的请求器。

// 引入 Request
import Request from '@/nPro/request/index.js'

// 设置 通用的 baseUrl 以及 header
const config = {
	baseUrl: baseUrl,
	header: {"content-type": "application/x-www-form-urlencoded"}
}

// 设置自己的请求拦截器,必须加上 `async`
// 请求前的拦截,比如是否登录/过期/刷新token/...
const reqInterceptor = async (options) => {
	// 必须返回一个 Object
	// 拦截请求:return {nReqToCancel: true, ...}
	// TODO: 添加任意拦截逻辑
	return options
}

// 设置自己的响应拦截器
// 统一对返回的数据进行整理,方便接口统一使用
// conf是您api的options信息,一般情况下您只需要用到您自定义的标记字段
const resInterceptor = (response, conf={}) => {
	// 必须返回你需要处理的数据,将会进入resolve(then中处理)
	// 如果需要reject,需要设置nReqToReject:true,还可以携带自己定义的任何提示内容(catch中处理)
	// uni.request进入fail也会进入该拦截器(为了统一处理逻辑),这个时候的response参数为{nFail: true, response: fail info}。fail时不管返回啥,都进入reject(catch)
	if (response.nFail) {
		return response.response
	}
	// 请求被拦截时也会进入该回掉(为了统一处理逻辑),这个时候的response参数为{nCancel: true, response: cancel info}。cancel时不管返回啥,都进入reject(catch)
	if (response.nCancel) {
		return response.response
	}
	return response
}

// 实例化请求器
// 您可以根据需要实例化多个请求器
const req = new Request(config, reqInterceptor, resInterceptor)

export default req

构建api或者直接使用 #

我们使用了一些固定的参数来定义请求的类别:

  • type: request-普通请求,upload-上传,download-下载;
  • task: 布尔值,是否返回task任务,默认是不返回 false;

我们使用了一些固定的参数来标记拦截状态:

  • nReqToCancel: 布尔值。请求拦截器的返回里标记是否拦截请求;
  • nCancel: 布尔值。响应拦截器回掉参数中,标记请求是否被拦截;
  • nFail: 布尔值。响应拦截器回掉参数中,标记是否进入了uni.requestfail,具体可以看拦截器示范;
  • nReqToReject:布尔值。用于响应拦截器里面的返回内容标记,标记是否进入reject

构建api #

import request from '@/common/request.js'

// baseUrl: 'https://www.baidu.com'
// 在您需要请求的地方直接使用该api
export function editInfo(data) {
	return request.request({
		url: '/search',
		method: 'POST',
		data: data
	})
}
import { editInfo } from '@/api/user.js'

export default {
	methods: {
		changeUserInfo() {
			editInfo({name: 'nickname'}).then(res => {
				// success
			}).catch(err => {
				// error
				// err 有可能是 Error 对象,也有可能是 您自己定义的内容,处理的时候您需要自己判断
				// 一个通用的错误提示组件就可以完成
			})
		}
	}
}

直接使用 #

import request from '@/common/request.js'

export default {
	methods: {
		changeUserInfo() {
			request.request({
				url: '/edit_info',
				data: {name: 'nickname'},
				method: 'POST'
			}).then(res => {
				// success
			}).catch(err => {
				// error
			})
		}
	}
}

当然,您也可以在其它js中使用,比如store

task #

api #

export function upVideoProject(file, name, data={}, success=null, fail=null, complete=null) {
	return req.request({
		url: '/projects/video_upload/',
		filePath: file,
		name: name,
		formData: data,
		type: 'upload',
		task: true
	}, success, fail, complete)
}

获取task #

使用async/await获取

try{
	const a = await upVideoProject(this.videoSrc, 'video', {name: this.name.trim()}, (suc)=>{
		// 其实就是resolve/then
		console.log('a success', suc)
	}, (fail) => {
		// 其实就是reject/catch
		console.log('a fail', fail)
	}, (com) => {
		// 通用逻辑
		console.log('a complete', com)
	})
	console.log('a task:', a)
	a.onProgressUpdate = (pg) => {
		console.log(pg.progress)
	}
}catch(e){
	//TODO handle the exception
	console.log('try:e:', e)
}
console.log('hi')

then获取

const a = upVideoProject(this.videoSrc, 'video', {name: this.name.trim()}, (suc)=>{
	console.log('success', suc)
}, (fail) => {
	console.log('fail', fail)
}, (com) => {
	console.log('complete', com)
})
console.log('task:', a)
a.then(res => {
	console.log('res:', res)
	res.onProgressUpdate = (pg) => {
		console.log(pg.progress)
	}
}).catch(err => {
	console.log('err:', err)
})
console.log('hello')

success/fail/complete回掉 #

  • success/fail/complete都支持全局配置和局部配置,全局和局部并不是覆盖关系,而是都会运行。先运行全局配置,然后是局部配置;
  • 所有的回掉都有一个参数,该参数就是响应拦截器里面您的返回内容;
  • success/fail/complete回掉并不对应uni.request的相应回掉,而是对应您的业务逻辑,resolve/then的就是successreject/catch的就是fail
  • task任务中,业务处理在success/fail/complete回掉中,毕竟不再是常规的then/catch处理;

全局配置 #

const sucH = (res)=>{}
...
const req = new Request(config, reqInter, resInter, sucH, failH, comH)

局部配置 #

参考上面的task api处理方式。

建议 #

在构建api或者使用request的时候,您可以根据需要在参数里面增加字段,这样您可以根据自己的字段在拦截器里面做更多的事情。

比如 #

export function login(data) {
	return request.request({
		url: '/login',
		method: 'POST',
		data: data,
		authType: 'None'
	})
}

我们在options里面增加了一个authType参数,这样我们在构建拦截器的时候可以根据这个参数来判断该接口是否需要登录授权

// 需要登录的拦截掉,不需要登录的通过请求
const reqInterceptor = async (options) => {
	if (options.authType === 'None') {
		return options
	}
	return false
}

更多 #

这就是一个最简单直接的请求库,你可以查看源码,从而根据自己的需要构建一个满意的拦截器响应器

其实就是根据你的接口配置信息以及拦截返回的数据进行判断,进一步去适配uni.request

一切需要的都可以通过拦截器来实现。