Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/40.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Node.js 如何使用request和nodejs基于响应头重试请求?_Node.js_Typescript_Request_Response Headers - Fatal编程技术网

Node.js 如何使用request和nodejs基于响应头重试请求?

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

我有一个小的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 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(文件,缓冲区)
写入

向下