使用节点 https get 请求强制纯文本编码
Force plain text encoding with node https get request
问题
与 相关 - 但这个答案对我不起作用。
我正在尝试调用 Stack Overflow API questions 端点:
https://api.stackexchange.com/2.3/questions?site=Whosebug&filter=total
哪个应该 return 以下 JSON 响应:
{"total":21951385}
示例代码
我正在使用这样的 https
node module to submit a get
请求:
const getRequest = (url: string) => new Promise((resolve, reject) => {
const options: RequestOptions = {
headers: {
'Accept': 'text/*',
'Accept-Encoding':'identity',
'Accept-Charset' : 'utf8',
}
}
const req = get(url, options, (res) => {
res.setEncoding('utf8');
let responseBody = '';
res.on('data', (chunk) => responseBody += chunk);
res.on('end', () => resolve(responseBody));
});
req.on('error', (err) => reject(err));
req.end();
})
然后像这样调用它:
const questionsUrl = 'https://api.stackexchange.com/2.3/questions?&site=Whosebug&filter=total'
const resp = await getRequest(questionsUrl)
console.log(resp)
但是,我得到了回复:
▼�
�V*�/I�Q�22�454�0�♣��♥‼���↕
我尝试过的
我试过做以下几种变体:
我正在通过流向 setEncoding
呼叫 utf8
我已经将 Accept
header 设置为 text/*
-
Provides a text MIME type, but without a subtype
我已经将 Accept-Encoding
header 设置为 identity
-
Indicates the identity function (that is, without modification or compression)
此代码也适用于几乎任何其他 API 服务器,例如使用以下 url:
https://jsonplaceholder.typicode.com/todos/1
但是 StackOverlow API 在我尝试过的任何其他地方都可以使用,因此必须有一种方法来指示节点如何执行它。
响应头 - 内容编码 - Gzip
正如 指出的那样 - 看起来服务器不尊重正在传递的 Accept-Encoding
值并返回压缩响应 none-the-less.
解压缩响应
根据How do I ungzip (decompress) a NodeJS request's module gzip response body?上的回答,可以这样解压:
import { get } from 'https'
import { createGunzip } from 'zlib'
const getRequest = (url: string) => new Promise((resolve, reject) => {
const req = get(url, (res) => {
const buffer: string[] = [];
if (!res.headers['content-encoding']?.includes('gzip')) {
console.log('utf8')
res.on('data', (chunk) => buffer.push(chunk));
res.on('end', () => resolve(buffer.join("")))
} else {
console.log('gzip')
const gunzip = createGunzip();
res.pipe(gunzip);
gunzip.on('data', (data) => buffer.push(data.toString()))
gunzip.on("end", () => resolve(buffer.join("")))
gunzip.on("error", (e) => reject(e))
}
});
req.on('error', (err) => reject(err));
req.end();
})
我的建议是使用内置支持 promises 和 gzip 的 http 库。我目前最喜欢的是 got()
。 http.get()
就像任何地方功能最少的 http 请求库。你真的不必自己写所有这些。这是使用 got() 库的整个代码的样子:
const got = require('got');
function getRequest(url) {
return got(url).json();
}
这个库会自动处理你需要的所有这些事情:
- 承诺
- JSON 转换
- Gzip解码
- 2xx 状态检测(其他状态代码如 404 会变成您的代码不会执行的承诺拒绝)。
而且,它还有许多其他一般用途的有用功能。使用 http.get()
手动编码的日子应该早已结束。无需重写已经为您编写并经过良好测试的代码。
仅供参考,这里有一个非常强大的 http 库列表:https://github.com/request/request/issues/3143。您可以选择您最喜欢的API。
问题
与
我正在尝试调用 Stack Overflow API questions 端点:
https://api.stackexchange.com/2.3/questions?site=Whosebug&filter=total
哪个应该 return 以下 JSON 响应:
{"total":21951385}
示例代码
我正在使用这样的 https
node module to submit a get
请求:
const getRequest = (url: string) => new Promise((resolve, reject) => {
const options: RequestOptions = {
headers: {
'Accept': 'text/*',
'Accept-Encoding':'identity',
'Accept-Charset' : 'utf8',
}
}
const req = get(url, options, (res) => {
res.setEncoding('utf8');
let responseBody = '';
res.on('data', (chunk) => responseBody += chunk);
res.on('end', () => resolve(responseBody));
});
req.on('error', (err) => reject(err));
req.end();
})
然后像这样调用它:
const questionsUrl = 'https://api.stackexchange.com/2.3/questions?&site=Whosebug&filter=total'
const resp = await getRequest(questionsUrl)
console.log(resp)
但是,我得到了回复:
▼�
�V*�/I�Q�22�454�0�♣��♥‼���↕
我尝试过的
我试过做以下几种变体:
我正在通过流向
setEncoding
呼叫utf8
我已经将
Accept
header 设置为text/*
-Provides a text MIME type, but without a subtype
我已经将
Accept-Encoding
header 设置为identity
-Indicates the identity function (that is, without modification or compression)
此代码也适用于几乎任何其他 API 服务器,例如使用以下 url:
https://jsonplaceholder.typicode.com/todos/1
但是 StackOverlow API 在我尝试过的任何其他地方都可以使用,因此必须有一种方法来指示节点如何执行它。
响应头 - 内容编码 - Gzip
正如 Accept-Encoding
值并返回压缩响应 none-the-less.
解压缩响应
根据How do I ungzip (decompress) a NodeJS request's module gzip response body?上的回答,可以这样解压:
import { get } from 'https'
import { createGunzip } from 'zlib'
const getRequest = (url: string) => new Promise((resolve, reject) => {
const req = get(url, (res) => {
const buffer: string[] = [];
if (!res.headers['content-encoding']?.includes('gzip')) {
console.log('utf8')
res.on('data', (chunk) => buffer.push(chunk));
res.on('end', () => resolve(buffer.join("")))
} else {
console.log('gzip')
const gunzip = createGunzip();
res.pipe(gunzip);
gunzip.on('data', (data) => buffer.push(data.toString()))
gunzip.on("end", () => resolve(buffer.join("")))
gunzip.on("error", (e) => reject(e))
}
});
req.on('error', (err) => reject(err));
req.end();
})
我的建议是使用内置支持 promises 和 gzip 的 http 库。我目前最喜欢的是 got()
。 http.get()
就像任何地方功能最少的 http 请求库。你真的不必自己写所有这些。这是使用 got() 库的整个代码的样子:
const got = require('got');
function getRequest(url) {
return got(url).json();
}
这个库会自动处理你需要的所有这些事情:
- 承诺
- JSON 转换
- Gzip解码
- 2xx 状态检测(其他状态代码如 404 会变成您的代码不会执行的承诺拒绝)。
而且,它还有许多其他一般用途的有用功能。使用 http.get()
手动编码的日子应该早已结束。无需重写已经为您编写并经过良好测试的代码。
仅供参考,这里有一个非常强大的 http 库列表:https://github.com/request/request/issues/3143。您可以选择您最喜欢的API。