nodeJs中undici请求库的使用

更新日期: 2021-10-21阅读: 2k标签: 请求

由于request在2020 年 2 月 11 日已经标记为弃用,在 npm 基本上搜索不到了,除非直接访问地址。在这之后 node-fetch、axios 也许是一个不错的选择,但在Node.js官方有一个请求库undici,undici 是意大利语 11 的意思,它比内置的 HTTP 模块还要快,下文有基准测试数据。undici 团队致力于为 Node.js 开发快速、可靠且符合规范的 HTTP 客户端。


基准测试

下面是一个在 Node.js 16 上做的一个基准测试,通过与最慢的数据做对比,之间相差还是挺大的。

Connections 1

TestsSamplesResultToleranceDifference with slowest
http - no keepalive154.63 req/sec± 2.77 %-
http - keepalive104.81 req/sec± 2.16 %+ 3.94 %
undici - stream2562.22 req/sec± 2.67 %+ 1244.58 %
undici - dispatch1564.33 req/sec± 2.47 %+ 1290.24 %
undici - request1566.08 req/sec± 2.48 %+ 1327.88 %
undici - pipeline1066.13 req/sec± 1.39 %+ 1329.08 %

Connections 50

TestsSamplesResultToleranceDifference with slowest
http - no keepalive503546.49 req/sec± 2.90 %-
http - keepalive155692.67 req/sec± 2.48 %+ 60.52 %
undici - pipeline258478.71 req/sec± 2.62 %+ 139.07 %
undici - request209766.66 req/sec± 2.79 %+ 175.39 %
undici - stream1510109.74 req/sec± 2.94 %+ 185.06 %
undici - dispatch2510949.73 req/sec± 2.54 %+ 208.75 %
数据来源:https://github.com/nodejs/undici

上手

这是一个 NPM 模块,首先你需要安装且引用它,为了能够方便的使用 Top Level Await 这一特性,下文使用 ES Modules 模块规范。

npm i undici -S
import undici from 'undici';

undici 对外暴露一个对象,该对象下面提供了几个 api

  • undici.fetch:发起一个请求,和浏览器中的 fetch 方法一致;
  • undici.request:发起一个请求,和 request 库有点类似,该方法支持 Promise;
  • undici.stream:处理文件流,可以用来进行文件的下载;

undici基础使用

开启一个 Server

开始之前让我们先开启一个 Server,稍后我们使用 undici 的 HTTP 客户端请求本地的 Server 做一些测试。

// server.mjs
import http from 'http';
const server = http.createServer((req, res) => {
res.end(`Ok!`);
});
server.listen(3000, () => {
console.log('server listening at 3000 port');
});

// 终端启动
node server.mjs

使用 request 请求接口

它的返回结果支持异步迭代迭代器,你可以使用 for await...of 遍历返回的 body 数据。

const {
statusCode,
headers,
trailers,
body
} = await undici.request('http://localhost:3000/api', {
method: 'GET'
});
console.log('response received', statusCode)
console.log('headers', headers)
for await (const data of body) {
console.log('data', data.toString());
}
console.log('trailers', trailers)

创建一个 client 实例请求接口

undici 提供了 Client 类,可以传入 URL 或 URL 对象,它仅包括协议、主机名、端口,用于预先创建一个基础通用的客户端请求实例。

我们还可以对返回结果监听 'data' 事件,获取响应的数据,就好比之前以流的方式从文件读取数据,监听 'data' 事件,不过现在以流的方式读取数据也支持异步迭代。

const client = new undici.Client('http://localhost:3000');
const { body } = await client.request({
path: '/api',
method: 'GET',
});
body.setEncoding('utf-8');
body.on('data', console.log);
body.on('end', () => console.log('end'));

使用 stream() 方法做接口代理

与 request 方法不同,client.stream 方法期望 factory 返回一个将写入 Response 的 Writable。当用户期望直接将 response body 传递到 Writable 时,通过避免创建一个中间的 Readable 来提高性能。

const factory = ({ opaque: res }) => res;
const client = new undici.Client('http://localhost:3000');
http.createServer((req, res) => {
client.stream({
path: '/',
method: 'GET',
opaque: res
}, factory, (err) => {
if (err) {
console.error('failure', err)
} else {
console.log('success')
}
});
}).listen(3010);

使用 stream 从网络读取一张图片写入本地

如果对上个例子 undici.stream 的使用还不了解的,在看看下面这个场景,首先从网络读取图片,返回值本身就是一个可读流对象,现在通过 opaque 指定一个可写流,这个时候图片在读取的过程中就会不断流入到可写流对象所指向的文件。

const factory = ({ opaque: res }) => res;
const url = 'https://images.pexels.com/photos/3599228/pexels-photo-3599228.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500';
undici.stream(url, {
opaque: fs.createWriteStream('./pexels-photo-3599228.jpeg')
}, factory, (err) => {
if (err) {
console.error('failure', err)
} else {
console.log('success')
}
});

在之前是这样做的。

import request from 'request';
import fs from 'fs';
const readable = request('https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image&quality=100&size=b4000_4000&sec=1586785739&di=ba1230a76a1ebd25200448d5cf02ec40&src=http://bbs.jooyoo.net/attachment/Mon_0905/24_65548_2835f8eaa933ff6.jpg');
const writeable = fs.createWriteStream('./pexels-photo-3599228.jpeg');
readable.pipe(writeable)
readable.on('error', function(err) {
writeable.close();
});

中止一个请求

可以使用控制器对象 AbortController 或 EventEmitter 中止一个客户端请求。要在 v15.x 之前的版本使用 AbortController 的需要先安装并导入该模块。最新的 v15.x 版本是不需要的,已默认支持。

// npm i abort-controller
import AbortController from "abort-controller"

const abortController = new AbortController();
client.request({
path: '/api',
method: 'GET',
signal: abortController.signal,
}, function (err, data) {
console.log(err.name) // RequestAbortedError
client.close();
});
abortController.abort();

除此之外,任何发出 'abort' 事件的 EventEmitter 实例,都可用作中止控制器。

import { EventEmitter } from 'events';
const ee = new EventEmitter();
client.request({
path: '/api',
method: 'GET',
signal: ee,
}, function (err, data) {
console.log(err.name) // RequestAbortedError
client.close();
});
ee.emit('abort');

undici-fetch

这是一个构建在 undici 之上的 WHATWG fetch 实现,就像你之前使用 node-fetch 一样,你可以选择使用 undici-fetch 简单的处理一些请求。

// npm i undici-fetch
import fetch from 'undici-fetch';
const res = await fetch('http://localhost:3000');
try {
const json = await res.json();
console.log(json);
} catch (err) {
console.log(err);
}

总结

本文只是介绍了 undici 几个 api 的使用方式,看起来 undici 上手难道还是比较低的。但是兼容性还不太行,比如,fetch 只支持 node@v16.5.0 以上的版本。

对于这种比较新的库,个人还是建议多观望一段时间,虽然 request 已经废弃了,我们还是使用一些经过较长时间考验过的库,比如,egg 框架中使用的 urllib,还有一个 node-fetch,上手难道也比较低,与浏览器中的 fetch api 使用方式一致。


链接: https://fly63.com/article/detial/10747

nginx 301跳转https后post请求失效问题解决

强制把http请求跳转到https,结果发现App有部分的功能不能使用,因为App一共设置了4种请求方式,分别是GET,POST,DELETE和OPTIONS方式,设置301跳转后所有的请求方法都变成了GET方式,导致一些功能无法正常使用.

HTTP请求的11个处理阶段

几乎所以有关Nginx书只要是讲深入点的就会讲到Nginx请求的11个处理阶段,要记住这些真是不易,人脑特别不擅长记住各种东西,只能做些索引罢了,能做到知道这个知识点在哪儿能找到不就行了,可是你去面试还是问这些理论,所以这里汇总下记录如下

http请求过程的7个步骤

HTTP通信机制是在一次完整的HTTP通信过程中,Web浏览器与Web服务器之间将完成下列7个步骤:建立TCP连接、Web浏览器向Web服务器发送请求命令、Web浏览器发送请求头信息、 Web服务器应答

http请求的几种类型

http请求中的8种请求方法:opions 返回服务器针对特定资源所支持的HTML请求方法 ,Get 向特定资源发出请求,Post 向指定资源提交数据进行处理请求

nodejs http请求相关总结

通过node提供的http模块,可以通过其提供的get()和request()两个方法发起http请求,get()是对request()方法的封装,方便发起get请求,如果要实现post请求,那么需要对request()方法进行封装。

ajax异步请求302分析

遇到这样一种情况,打开网页两个窗口a,b(都是已经登录授权的),在a页面中退出登录,然后在b页面执行增删改查,这个时候因为授权原因,b页面后端的请求肯定出现异常(对这个异常的处理,进行内部跳转处理),b页面中的ajax请求的回调中就会出现问题

POST 请求的三种常见数据提交格式

本文所讲的 POST 请求是 HTTP/1.1 协议中规定的众多 HTTP 请求方法的其中最常用的一个。一般使用 POST 请求方法向服务器发送数据(主要是一些创建更新操作),本文讨论的是 POST 请求方法常用的四种数据提交格式。

flutter之网络请求dio封装,拦截器的封装

flutter一直很火的网络请求插件dio,直接上代码,写成一个类,可以直接使用,包含请求的封装,拦截器的封装

HTTP请求过程

当我们在web浏览器的地址栏中输入: www.baidu.com,然后回车,到底发生了什么?DNS域名解析采用的是递归查询的方式,过程是,先去找DNS缓存->缓存找不到就去找根域名服务器->根域名又会去找下一级

nginx是怎么处理http请求的?

nginx首先决定要用配置文件里的哪个server{}块来处理,假设有下面的server{}配置;nginx会根据过来的http请求头里的Host字段里的值,来判断使用哪个server{}。

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!