ryoko

a requestion lib based on the fetch native api

Usage no npm install needed!

<script type="module">
  import ryoko from 'https://cdn.skypack.dev/ryoko';
</script>

README

ryoko

ryoko,一个基于浏览器原生Fetch API的HTTP请求库。


特性

  • 简易API设计
  • 全局响应和请求拦截器
  • 局部钩子:beforeRequest、afterResponse
  • 延迟和手动终止一个或多个请求
  • 下载进度监听
  • URL前缀、Status验证
  • 快捷操作语法,如:ryoko.post()
  • 完善的错误提示

安装

使用npm:

npm install ryoko -S

使用cdn:

//unpkg
<script src="https://unpkg.com/ryoko/dist/ryoko.min.js"></script>

//jsdelivr
<script src="https://cdn.jsdelivr.net/npm/ryoko/dist/ryoko.min.js"></script>

API


ryoko(config)

通过传入config配置选项来新建一个ryoko请求

import ryoko from 'ryoko';

ryoko({
    method: 'post',
    url: '/guoxiaoyou/lalaal',
    data: {
        name: 'haha',
        age: 13,
    }
}).then(res => {
    console.info(res.data)
})

或者使用别名,如:

ryoko.get(url, config?)
ryoko.post(url, config?)
ryoko.put(url, config?)
ryoko.patch(url, config?)
ryoko.delete(url, config?)
ryoko.head(url, config?)


config配置详情:

{
    //请求方法,默认为get
    method: 'post',
    
    //请求的url
    url: '/guoxiaoyou',
    
    //prefixUrl,请求url的前缀,默认:''空字符串
    prefixUrl: 'https://www.guoxiaoyou.cn',
    
    //url查询参数,类型:String | PlainObject纯对象 | URLSearchParams
    params: {
        name: 'guoxiaoyou'.
        age: '10'
    },
    
    //headers为自定义请求头,类型:Headers | Record<string,string>
    headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
    },
    
    //data请求体,用于fetch.body选项,类型:BodyInit
    //若为PlainObject纯对象,如{a:2,b:3},内部将使用JSON.stringify转译
    data: new URLSearchParams(),
    
    //超时时间,默认0,即不取消请求
    timeout: 10000,
    
    //超时后触发的函数,参数:超时取消信息
    onDefer(deferMsg){
        
    },
    
    //下载进度监听
    downloadScheduler({
        percent, //百分百
        total, //总长度(字节)
        received, //当前得到的长度
        buffer, //所得资源二进制数据
    }) {
        
    }
    
    //响应状态码验证
    verifyStatus(status) {
        return status > 200
    },
    
    //请求前钩子
    beforeRequest(config) {
        
    },
    
    //响应后钩子
    afterResponse(response) {
    
    },
    
    //终止请求令牌
    abortToken,
    
    //是否自动携带上cookie,默认'same-origin‘(同源情况下),其它可选值:'omit'、'include'
    //特别的,为true时,即表示'include',false对应'omit'
    credentials: true,
    
    //响应数据类型,默认:'text',其它可选值:'arrayBuffer' | 'text' | 'json' | 'formData' | 'blob'
    responseType: 'json',
    
    //自定义fetch函数,如引入的polyfill
    fetch: fetchPolyfill
    
}

除此之外还继承了fetch请求原生的mode、integrity、redirect、cache、referrer、referrerPolicy等配置选项。详见(MDN之fetch API文档参考


ryoko静态方法或属性

  • ryoko.AbortTokenizer:终止ryoko请求的令牌控制器

  • ryoko.create:创建一个新的请求实例

  • ryoko.all:并发处理(等待多个)ryoko请求,基于Promise.all实现

  • ryoko.spread:可在处理完并发请求后调用,如:

    const req = ryoko.get('/ddd')
    const req2 = ryoko.get('/ccc')
    
    ryoko.all(req, req2).then(ryoko.spread((res1, res2) => {
      //res1、res2分别对应第一、二个请求的响应结果
    }))
    
  • ryoko.Ryoko:即ryoko请求对象的原始构造类


创建ryoko实例

使用ryoko.create方法即可创建新的请求实例,一般还会传递一些默认参数,如timeout、prefixURL等。

const anfrage = ryoko.create({
    timeout: 1000,
    prefixURL: 'https://www.guoxiaoyou.cn'
})
anfrage.defaults.onDefer = function() { 
    console.info('请求超时了')
}

注意,若后续请求中具有相同配置,则遵循后入为主原则。如:

anfrage.get('/ddd', {
    timeout: 800
})

此时timeout为800毫秒。


拦截器

在正式请求前或响应后砸门往往需要处理某些工作,如给请求头加上token、loading动画加载等,拦截器则能很好地满足需求。如:

//请求拦截器
ryoko.interceptors.request.use((config) => {
    config.headers['Authorization'] = localStorage.getItem('token');
    return config;
},(err) => {
    return Promise.reject(err)
})

//响应拦截器
ryoko.interceptors.response.use(function(response) {
    return response
}, (err) => {
    return Promise.reject(err)
})

如果需要移除拦截器,可使用:

const inter = ryoko.interceptors.response.use((res) => {
    return res
})
ryoko.interceptors.response.eject(inter);

特别的,需要注意拦截器与局部钩子beforeRequest、afterResponse的差异。比如说:

1、执行顺序上:全局request拦截器 > 局部beforeRequest钩子 > 局部afterResponse钩子 > 全局response拦截器

//请求拦截器
ryoko.interceptors.request.use((config) => {
    console.info(1)
    return config;
})

//响应拦截器
ryoko.interceptors.response.use(function(response) {
    console.info(4)
    return response
})

ryoko.get({
    beforeRequest(config) {
        console.info(2)
    },
    afterResponse(response) {
        console.info(3)
    }
})

//执行后依次打印:1、2、3、4

2、全局拦截器必须将config或response参数返回,局部的beforeRequest、afterResponse钩子则不作要求;


下载进度监听

前文已经提及,在配置选项中加入downloadSchduler即可监听下载进度。如:

ryoko.get('/ddd', {
    downloadSchduler({percent, received, total, buffer}) {
        
    }
})

该方法接受一个形参:downloadInfo下载信息,该参数又包含四个属性:

  • percent:下载进度百分比
  • received:实时获取的字节长度
  • total:总字节长度
  • buffer:获取到的资源数据(Uint8Array类型)

注意点:此方法基于请求响应头的Content-length实现(因为fetch并未提供类似XHR的原生下载进度监测事件),所以对于没有Content-Type响应头参数的会无效。


ryokoResponse响应数据

{
    //请求配置,类型:ryokoMergeConfig
    config,
    
    //headers响应头,类型:PlainObject纯对象
    headers,
    
    //响应状态码
    status,
    
    //响应状态内容
    statusText,
    
    //fetch请求返回值
    source,
    
    //被处理后的fetch请求返回值,如res.json()
    data
}

注意,data是根据传入的responseType才被处理后的响应数据,而source选项才是真正的fetch请求后的返回值。

取消请求控制

第一种是设置timeout,若请求超时,则自动终止,同时触发onDefer回调。此外,用户也可手动取消。如:

import ryoko, { abortPendingRequest } from 'ryoko'

//获取请求终止令牌器
const AbortTokenizer = ryoko.AbortTokenizer;

// 创建一个终止令牌
const creatorToken = AbortTokenizer.createToken();

//再讲令牌token赋值给请求
ryoko.get('/ddd', {
    abortToken: creatorToken
})

//延迟120毫秒取消请求(如果该请求未完成)
setTimeout(() => {
    abortPendingRequest(creatorToken)
}, 120)

上述代码可以看到,取消一个请求需经过三个步骤:首先拿到终止控制器(AbortTokenizer),然后通过createToken方法创建终止令牌标识(一个Symbol值),它需赋予请求的abortToken选项,后续借助调abortPendingRequest方法便可取消对应请求。

同样,该方法适用于取消多个请求场景。如:

写法一:abortToken添加在基础配置选项上


const AbortTokenizer = ryoko.AbortTokenizer;
const creatorToken = AbortTokenizer.createToken();

let afrange = ryoko.create({
    abortToken: creatorToken
})

anfrage.get('/ddd', {
    params: {
        age: 10
    }
})

anfrage({
    method: 'post',
    url: '/sss',
    data: JSON.strigify({a:1,b:2})
})

//此时两个请求都将被取消(如果还没请求完成)
setTimeout(() => {
    abortPendingRequest(createToken)
}, 20)

写法二:逐个添加abortToken

const AbortTokenizer = ryoko.AbortTokenizer;
const creatorToken = AbortTokenizer.createToken();
 
ryoko.get('/ddd', {
    params: {
        age: 10
    },
    abortToken: creatorToken
})

ryoko({
    method: 'post',
    url: '/sss',
    data: JSON.strigify({a:1,b:2}),
    abortToken: creatorToken
})

//此时两个请求都将被取消(如果还没请求完成)
setTimeout(() => {
    abortPendingRequest(createToken)
}, 20)

关于运行环境

ryoko提供fetch选项方便用户使用自定义fetch方法。如对于在2015年之前发布的、不支持fetch的浏览器,可引入whatwg-fetch、node环境也可依托node-fetch。

//在老版浏览器
import {fetch as fetchPolyfill} from 'whatwg-fetch';

ryoko({
    url: 'ddd',
    fetch: fetchPolyfill
})

//在node环境
const fetchNode = require('node-fetch');
ryoko.get('/ddd', {
    fetch: fetchNode
})

作者

果小右——gejiuyuan.gitee.io😊