npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

puta

v1.2.4

Published

A request lib, encapsulation of axios.

Readme

puta

基于 axios , 但添加了许多有用的功能.

安装

$ npm install puta

使用

得到实例

import Puta form 'puta';

// 或
let puta = Puta({
  baseURL: xxx,
  timeout: 12000
});

let puta = new Puta({
  baseURL: xxx,
  timeout: 12000
});


进行请求:

puta.get('/user', {ID: '12345'})
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });
  
puta.post('/user', {ID: '12345'})
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

注册模块化的请求路径,

非必须, 详情查看下面文档 api .moduleRegister()为什么使用模块注册 的章节:

import Puta form 'puta';

let puta = Puta();

// 注册一个 menu 的路径模块
puta.moduleRegister({
  a: '/app',
  b: '/init.js',
}, 'menu')

// 注册一个  home 的路径模
// 路径除了是字符串, 还可以是对象 
puta.moduleRegister({
  c: '/app',
  d: {
    path: '/init.js',
    reqData: (data)=>{

      // 在 data 传递给请求之前, 可以处理下 data
      // 必须返回数据

      return data
    },
    use: (response)=>{
      
      // 在响应后, 可以处理下响应数据
      // 必须返回 数据

      return response
    },
    config: {} // puta config
  },
}, 'home')


// 然后你可以像下面这样请求

// mApis 保存着模块的命名空间
// 例如上面我们注册的 home 和 menu
puta.mApis.home.a(...rest) // get 请求
// 等价于 puta.get('/app', ...rest)

puta.mApis.home.a.post(...rest) //post
// 等价于 puta.post('/app', ...rest)

// apis 可以直接访问路径名, 无需加上模块名, 但需要警惕命名污染
puta.apis.a.post() //post
puta.apis.d.get() //此处 get可以省略

API

new Puta([config]) or puta([config])

config

Type: object

此 config 我们把它叫做 puta 的 config.

在不同阶段都可以传入 config 配置用于规划请求相关的行为, 详情查看: config 的层级覆盖

除了下面选项之外, 还可以参见: axios request-config

{
  stringfieldData: false, //  默认 false , 是否开启对 post 请求参数进行字符串化

  use: ()=>{}, // 一个函数, 对响应进行一次 use, 类似 axios.interceptors.response.use

  cancelUse: boolean, //是否取消 use, 在某些场景会用到
  
  cancel: object|function, // 取消请求用
  
}
stringfieldData

Type: boolean

是否对 post 请求的 request data 进行字符串序列化成 application/x-www-form-urlencoded 数据格式.

细节参见: :chicken::chicken:关于 post和 stringfieldData 配置项的关系

use

Type: function

类似传给axios.interceptors.response.use(fn)的第一个参数 fn, 此处的 use 函数会后于 axios.interceptors.response.use 执行.

cancelUse

取消 config 中 use 函数的执行.

更多信息查看: 为什么要在 config 中同时出现 use和 cancelUse

cancel

取消请求.

更多请查看: 如何取消请求

实例属性

.mApis

type: Proxy 调用 .moduleRegister() 后, 通过所注册的 api 路径的命名空间访问路径名;

如:

// 假如注册了两个模块, x 和 y
puta.moduleRegister({
  p1: '/ffds',
  p2: '/xxx',
},x)
puta.moduleRegister({
  p3: '/for_p3',
  p4: '/for_p4',
},y)

// 则可以通过如下方式访问相关路径来进行请求:
// 访问 p1,p2
puta.mApis.x.p1.post()
puta.mApis.x.p2.post()
// 访问 p3,p4
puta.mApis.y.p3.post()
puta.mApis.y.p3.post()


.apis

type: Proxy 调用 .moduleRegister() 后, 可以不通过命名空间直接访问路径名 如:

// 假如注册了两个模块, x 和 y
puta.moduleRegister({
  p1: '/ffds',
  p2: '/xxx',
  p5: '/for_x'
},x)
puta.moduleRegister({
  p3: '/for_p3',
  p4: '/for_p4',
  p5: '/for_y'
},y)

// 则可以通过如下方式访问相关路径来进行请求:
// 访问 p1,p2
puta.apis.p1.post()
puta.apis.p2.post()
// 访问 p3,p4
puta.apis.p3.post()
puta.apis.p3.post()

// 但要注意, p5在两个模块都有, 此时需要通过模块来访问路径
puta.mApis.x.p5.post()
puta.mApis.y.p5.post()

注意: 如果有两个以上的路径命名空间(模块)拥有同一个路径名, 但要警惕命名污染, 可能会产生非预期的结果.

实例方法

动词请求相关方法

.get(url [, params [, config]])
.delete(url [, params [, config]])
.head(url [, params [, config]])
.options(url [, params [, config]])
.post(url [,data, [,stringified] [,config]])
.put(url [,data, [,config]])
.patch(url [,data, [,config]])

如果通过已经注册了 api 模块, 则使用动词方法时可以省略第一个参数: url

  • config: puta 的 config
  • params: 传递的请求参数
  • data: 传递的请求参数
  • stringified: boolean, 类似 querystring.stringify() 一样序化请求体 . 你也可以传递一个对象, 这个时候就会被当做 config 来对待. 而 stringified 的值由 puta.options.stringfieldData 来决定

.all(Array<Promise>)

同 axios.all()

.setDefaults(callback)

callback 函数接收一个参数: axios实例的 defaults 属性, 可以在此修改一下默认 config, 这会覆盖 实例化 puta 时传入的 config

.reqUse(...args)

同 of axios.interceptors.request.use

.resUse(...args)

同 of axios.interceptors.response.use

.moduleRegister(apis, name, config)(重要) :sweet_potato::sweet_potato::sweet_potato:

更多细节查看: 为什么使用模块注册.

参数说明:

  • apis: 路径模块, type: object
  • name: 模块的命名空间, type: string
  • config: 这个模块的所有请求都会结合这个 config, puta的 config

关于 apis: 参数 : type: object

{
  // path 的值可以是字符串或对象
  path1: '',  // 值是一个字符串
  path2: { // 值是一个对象
    path: '', //required
    reqData: data=>data, // optional
    use: response=>response, //optional
    config: {}, //optional
  }
}
  • reqData 函数可以在 dataparams 传递给请求之前进行一些处理, 必须返回一个处理后的 data

  • use 函数可以在响应数据返回之后立即进行一些处理, 必须返回一个处理后响应数据.

  • config: puta 的 config , 只对 此请求路径有效

注册后模块后, 可以使用如下方式进行请求:

puta.apis.[method](...res)puta.mApis.[moduleName].[method]()

  • method 就是 get, post, head... 等动词请求方法.
  • moduleName 就是 moduleRegister 的第二个参数
  • ...rest : 就是参数列表, 其参数列表就是动词方法除去第一个参数:url 后剩余的参数别表, 比如
    • get: puta.apis.[method].get(params, config)
    • post: puta.apis.[method].post(data,[stringfield], config)

查看以下实例(为简化, 部分使用了伪代码), 注意阅读注释部分:

// 实例
let puta = Puta({
  baseURL: 'http://aaa.com'
});

let apis = puta.apis;

// 注册一个模块
// 处于演示需要, path的值我们故意使用两种形式, 字符串或对象
puta.moduleRegister({
  useInfo: '/user',
  goodsList: {
    path: '/goods',
    // reqData 是可选字
    reqData:data=>{
      data.addP = 'add'
      return data
    },
    // use 是可选字段
    use: res=>{
      res.x = 5;
      return x;
    }
    // config 是可选字段
    config: {
      baseURL: 'http://bbb.com'
    }
  },
}, home)



// 如果我们此时请求的路径是 goods:
// 请求的最终 url 本来是: 'http://aaa.com/goods', 但因为 config的配置,
// 变成了: 'http://bbb.com/goods'
apis.goodsList.get({
  mob: 'yesternight'
},{baseURL: 'http://mob.com', timeout: 1600})
  .then(res=>{
    // res 会先流过 use, 变成
    // {
    //   x:5,
    //   ...otherData
    // }
    console.log(res, '看看 res是什么')

  })

// {mob: 'yesternight'} 会流过 reqData, 变成
// {mob: 'yesternight', addP: 'add'}

// 事实上, 以上行为和以下行为是等价的: 

// request data 的处理环节
let data = (data=>{
  data.addP = 'add'
  return data
})({
  mob: 'yesternight'
})

// config 的覆盖情况
let config = Object.assign(
  {},
  {baseURL: 'http://aaa.com'},
  {baseURL: 'http://bbb.com'},
  {baseURL: 'http://mob.com', timeout: 1600}
)

puta.get('/goods', data, config)
.then(res=>{ // res 先被 use 处理
  res.x = 5;
  return x;
})
.then(res=>{
  console.log(res, '看看 res是什么')
})

:chicken::chicken:config 的层级覆盖

如果直接使用动词请求, config 会出现在 2 个层级:

  1. 新建实例时: Puta( [config] )
  2. 请求时, puta.get(params, [config] )

如果注册api 模块, 并通过模块路径访问请求: 那么 config 会出现在3 或 4 个层级:

  1. 新建实例时: Puta( [config] )
  2. 注册模块时: .moduleRegister(apis, name, [config] )
  3. api路径配置为对象时: apis = {a: {config: [config] }}
  4. 请求时: apis.a.get(params, [config] )

如果把 1,2,3,4 比喻为配置出现在的层级, 有两个或以上的地方出现 config 的时候, 相同的属性会出现覆盖,

高层级覆盖低层级的属性, 比如: 4 层级的会覆盖,3 层级的, 3 层级的会覆盖 2 层级的, 依次类推

:chicken::chicken:如何取消请求

你可以完全使用 axios 的取消请求的方式来进行取消请求的功能.

点击这里进行比较: axios cancel

但是 puta 也提供了另一种方式, 相比 axios 的方式更简洁.

可以像下面这样 使用puta.cancel() 创建一个取消函数, 查看如下代码:

let puta = Puta();

let cancel = puta.cancel();

puta.get('/user/12345', {
  cancel
}).catch(function (err) {
  if (err.isCancel) {
    console.log('Request canceled', thrown.message);
  } else {
    // handle error
  }
});

axios.post('/user/12345', {
  name: 'new name'
}, {
  cancel
})

// 取消请求 ( message 参数是可选的)
cancel('用户取消了请求');

也可以不使用 puta.cancel(), 而是给一个空对象:

let puta = Puta();

let cancel = {}

puta.get('/user/12345', {
  cancel
});

// 取消请求
cancel.cancel('请求被取消')

两种方式的异同, 相对来说第二种方式更加简洁, 但是需要提前取消请求只能使用第一中:

let puta = Puta();

let cancel1 = puta.cancel();

// 在 cancel1 函数传递给 config 之前就可以提前取消
cancel1('我被提前取消了');

puta.get('/user/12345', {
  cancel: cancel1
})


// =====================


let cancel2 = {};

puta.get('/user/12345', {
  cancel: cancel2
})

cancel.cancel('我只能被传递给 config 之后才能取消')

:chicken::chicken:关于 post和 stringfieldData 配置项的关系

在 axios 中, 提供了如何得到 application/x-www-form-urlencoded 数据格式的 方案.

这可能会引入一个额外的 qs 库来序列化字符串, 这类序列化的库实现了完整的序列化标准, 功能强大, 对于复杂的数据收发标准会很有用.

但是对于一些简单的数据收发标准(项目的大多数情况都是简单的), puta 提供了更轻量化的方案.

此方案只在 post 请求生效, 我们先看看 post 请求的函数格式:

puta.post(url [, data [,stringfield] [, config]] )

第三参数是可选的, 可以是 bool 值, 也可以省略或是个对象.

  • 如果是布尔值, 则代表含义是 stringfield 的值
  • 如果是个对象, 则代表的函数是 config 对象

stringfield 设置为 true 就会对 data 进行序列化处理:

let puta = Puta()

puta.post('/abc', {name: 'bob'}, true)
// 或者在 config 中进行配置
puta.post('/abc', {name: 'bob'}, {
  stringfieldData: true
})
// 以上两种方式是等价的

以上两种方式是等价的, 这意味着可以利用 config 的层次覆盖来得到 是否进行进行 stringfield, 查看如下代码:

// 在第一层级的 config 中设置
let puta = Puta({
  stringfieldData: true
})
// 此时数据会被格式化
puta.post('/abc', {name: 'bob'})

// 如果注册了api模块, 并且没设置 stringfieldDdata, 
// 此时由于层级覆盖的关系, 数据也会被格式化
// 下面这行是伪代码
puta.apis.a.post({name: 'bob'})

// 在更高层级设置 false 可以阻止格式
puta.post('/abc', {name: 'bob'}, false)
puta.apis.a.post({name: 'bob'}, false)

==========================

// 在 2 或 3 层级进行数据格式化
// 以在第二层为例
puta.moduleRegistery({cs: '/abc'}, 'x', {
  stringfieldData: true
})

// 此时数据也会被格式化
puta.apis.cs.post({name: 'bob'})

// 在更高层级设置 false 可以阻止格式
puta.apis.cs.post({name: 'bob'}, false)

res use 的执行顺序

req use 的执行顺序

关于缓存

:chicken::chicken: 为什么使用模块注册

:chicken::chicken: 为什么要在 config 中同时出现 use和 cancelUse

  • [ ] moduleRegister 第二个参数默认值为 default
  • [ ] puta 有初始实例化
  • [ ] 实例化隔开的缓存