Node.js 如何使用request和nodejs基于响应头重试请求?
我有一个小的nodejs脚本,我想下载一个zip文件:Node.js 如何使用request和nodejs基于响应头重试请求?,node.js,typescript,request,response-headers,Node.js,Typescript,Request,Response Headers,我有一个小的nodejs脚本,我想下载一个zip文件: const fs = requrie("fs"); const request = require("requestretry"); export class FileFetcher { public async fetchFile(url: string): Promise<string> { const fileName = "./download.zip"; return new
const fs = requrie("fs");
const request = require("requestretry");
export class FileFetcher {
public async fetchFile(url: string): Promise<string> {
const fileName = "./download.zip";
return new Promise<string>(resolve => {
request(url)
.pipe(fs.createWriteStream(fileName))
.on("close", function () {
resolve(fileName);
});
});
}
}
const fs=requurie(“fs”);
const request=require(“requestretry”);
导出类文件获取程序{
公共异步获取文件(url:string):承诺{
const fileName=“./download.zip”;
返回新承诺(解决=>{
请求(url)
.pipe(fs.createWriteStream(文件名))
.on(“关闭”,函数(){
解析(文件名);
});
});
}
}
我正在使用这个库,一个包装器,因为这个文件可能只存在于将来,因此很可能会在最初几次失败
然而,我必须适应我行为怪异的外部端点。它总是返回一个200 OK
,而不是预期的404 Not Found
因此,确定的唯一方法是响应中的内容长度
头。如果内容长度:0
,则没有文件
在requestretry
中似乎有不同的重试策略,但它们似乎都采用了一个完善的api,例如request.RetryStrategies.HTTPOrNetworkError
。因为它得到了一个200,它将永远不会重试并“成功”下载一个空的zip文件
我不习惯使用
requestretry
,我想知道如何根据响应头重试请求。您可以使用定义自己的重试逻辑,例如:
您可以定义自己的重试逻辑,例如:
我最终放弃了
requestretry
库,使用request
并自己实现了重试机制
一个问题是获取实际的反应体数据。我希望它可以通过响应
事件获得,但它只有标题
可以通过多个数据事件获取数据,并在结束事件上解析承诺
另一个问题是理解了请求需要如何发送,因为编码
需要为null,或者下载的文件被转换为字符串,因此被破坏
我的downloader类看起来像:
export class FileFetcher {
public async downloadWithRetry(url: string, maxRetries: number, timeout: number): Promise<Buffer> {
while (true) {
try {
const buffer = await this.fetchFile(url);
return new Promise<Buffer>(resolve => {
resolve(buffer);
});
} catch (e) {
maxRetries = maxRetries - 1;
if (maxRetries <= 0) {
throw new Error("Too many requests");
}
console.warn(`No file at url:${url}, waiting ...`);
await this.wait(timeout);
console.log(`Continue.`);
}
}
}
private async wait(timeout: number): Promise<any> {
timeout *= 1e3;
console.log(timeout);
return new Promise(resolve => {
setTimeout(resolve, timeout);
});
}
private async fetchFile(url: string): Promise <Buffer> {
return new Promise<Buffer>((resolve, reject) => {
let data = [];
request.get({
encoding: null,
url: url,
}).on("data", function (chunk) {
data.push(chunk);
}).on("response", function (response) {
/**
* Server always returns 200 OK even if file does not exist yet. Hence checking for content-lenth head
*/
if (!(response.headers["content-length"] > 0)) {
reject("Empty response!");
}
}).on("end", function () {
const body = Buffer.concat(data);
if (body.length > 0) {
resolve(body);
return;
}
reject("Empty response");
});
});
}
}
导出类文件获取程序{
公共异步下载WithRetry(url:string,maxRetries:number,timeout:number):承诺{
while(true){
试一试{
const buffer=wait this.fetchFile(url);
返回新承诺(解决=>{
解析(缓冲);
});
}捕获(e){
maxRetries=maxRetries-1;
如果(最大重试次数){
setTimeout(解析,超时);
});
}
私有异步获取文件(url:string):承诺{
返回新承诺((解决、拒绝)=>{
让数据=[];
请求({
编码:空,
url:url,
}).on(“数据”,函数(块){
数据推送(块);
}).on(“响应”),功能(响应){
/**
*即使文件还不存在,服务器也总是返回200 OK。因此检查内容长度头
*/
if(!(response.headers[“content length”]>0)){
拒绝(“空响应!”);
}
}).on(“结束”,函数(){
const body=Buffer.concat(数据);
如果(body.length>0){
决议(机构);
返回;
}
拒绝(“空响应”);
});
});
}
}
该缓冲区可以通过fs.writeFile(文件,缓冲区)
写入
缺点是不再使用流方法,因为我想通过管道传输数据。但这种方法至少可以正确地获取文件。我最终放弃了
requestretry
库,使用request
并自己实现了重试机制
一个问题是获取实际的响应主体数据。我希望它可以通过response
事件获得,但它只有标题
可以通过多个数据事件获取数据,并在结束事件上解析承诺
另一个问题是理解了请求需要如何发送,因为编码
需要为null,或者下载的文件被转换为字符串,因此被破坏
我的downloader类看起来像:
export class FileFetcher {
public async downloadWithRetry(url: string, maxRetries: number, timeout: number): Promise<Buffer> {
while (true) {
try {
const buffer = await this.fetchFile(url);
return new Promise<Buffer>(resolve => {
resolve(buffer);
});
} catch (e) {
maxRetries = maxRetries - 1;
if (maxRetries <= 0) {
throw new Error("Too many requests");
}
console.warn(`No file at url:${url}, waiting ...`);
await this.wait(timeout);
console.log(`Continue.`);
}
}
}
private async wait(timeout: number): Promise<any> {
timeout *= 1e3;
console.log(timeout);
return new Promise(resolve => {
setTimeout(resolve, timeout);
});
}
private async fetchFile(url: string): Promise <Buffer> {
return new Promise<Buffer>((resolve, reject) => {
let data = [];
request.get({
encoding: null,
url: url,
}).on("data", function (chunk) {
data.push(chunk);
}).on("response", function (response) {
/**
* Server always returns 200 OK even if file does not exist yet. Hence checking for content-lenth head
*/
if (!(response.headers["content-length"] > 0)) {
reject("Empty response!");
}
}).on("end", function () {
const body = Buffer.concat(data);
if (body.length > 0) {
resolve(body);
return;
}
reject("Empty response");
});
});
}
}
导出类文件获取程序{
公共异步下载WithRetry(url:string,maxRetries:number,timeout:number):承诺{
while(true){
试一试{
const buffer=wait this.fetchFile(url);
返回新承诺(解决=>{
解析(缓冲);
});
}捕获(e){
maxRetries=maxRetries-1;
如果(最大重试次数){
setTimeout(解析,超时);
});
}
私有异步获取文件(url:string):承诺{
返回新承诺((解决、拒绝)=>{
让数据=[];
请求({
编码:空,
url:url,
}).on(“数据”,函数(块){
数据推送(块);
}).on(“响应”),功能(响应){
/**
*即使文件还不存在,服务器也总是返回200 OK。因此检查内容长度头
*/
if(!(response.headers[“content length”]>0)){
拒绝(“空响应!”);
}
}).on(“结束”,函数(){
const body=Buffer.concat(数据);
如果(body.length>0){
决议(机构);
返回;
}
拒绝(“空响应”);
});
});
}
}
该缓冲区可以通过fs.writeFile(文件,缓冲区)
写入
向下