如何在nodejs中进行同步http get?

问题描述 投票:0回答:3

我有一个基于 txt 文件内的值调用 API 的代码。 在每次 API 调用中,代码都会从响应 JSON 中提取一些信息并构造一个 csv。 每次完成对 API 的 HTTP get 调用时,我都会通过覆盖 csv 来使代码正常工作。但是,为了提高效率,我宁愿只写一次 csv。我当前的代码是这样的......

const fs = require("fs");
const https = require("https");
var text = ""
fs.readFile(filename, 'utf8', function(err, data) {
    if (err) reject(error);
    issns = data.split(/\r?\n/)
    getPolicies(issns);
});

function getPolicies(issns){
    for (let i = 0; i<issns.length; i++){
        url = "some_api_url" + issns[i]
        https.get(url, (resp) => {
            let data = '';
            resp.on('data', (chunk) => {
                data += chunk;
            });
            resp.on('end', () => {
                data = JSON.parse(data)
                constructCSV(issns[i], data)
            });
            }).on("error", (err) => {
                console.log("Error: " + err.message);
        });
    }
}
function constructCSV (issn, data){
    // code to get some data from the json in parameter "data"
    // ...
    // ...
    saveOutput()            
}
function saveOutput(){
    fs.writeFileSync(output_file_dir, text);
}

如前所述,我宁愿只调用 saveOutput() 一次,如果可能的话,在调用 getPolicies() 之后立即调用。然而,由于获取策略使用异步 http get,这会导致空白 csv 文件。

如果有人可以帮助我,我将非常感激!

node.js asynchronous https synchronization
3个回答
0
投票

嗯,看来你并不真正需要同步请求,而是检测所有请求何时完成。

一个简单的解决方案是跟踪最后一个请求,然后将其作为参数传递给

constructCSV
,然后在所有请求完成标志时调用
saveOutput

// send last request flag
constructCSV(issns[i], data, i+1==issns.length)

//...

// write on the last request flag
function constructCSV (issn, data, done){
    // code to get some data from the json in parameter "data"
    // ...
    // ...
    if(done) saveOutput()            
}

0
投票

我制作了sync-request-curl,它可以帮助同步请求如果你想避免承诺或

async
/
await
出于任何原因

sync-request-curl 一个库,包含原始 sync-request 中的功能子集,但利用 node-libcurl 在 NodeJS 中获得更好的性能。

这是 GET 请求的基本用例:

// import request from 'sync-request-curl';
const request = require('sync-request-curl');
const response = request('GET', 'https://ipinfo.io/json');
console.log('Status Code:', response.statusCode);
console.log('body:', response.body.toString());

在性能方面,它与异步等效项(例如then-request)相当,不过,我再次建议如果可能的话,研究promises/

async
/
await

具体到您的情况,当以同步方式完成时,它可能看起来像这样:

const fs = require("fs");
const request = require("sync-request-curl");

const issns = fs.readFileSync(filename, "utf-8").split(/\r?\n/);

const csvData = [];

function getPolicies(issns) {
  for (const issn of issns) {
    const url = "some_api_url" + issn;
    const response = request("GET", url);
    if (response.statusCode === 200) {
      const data = JSON.parse(response.getBody("utf8"));
      constructCSV(issn, data);
    } else {
      console.error("Error fetching data for ISSN: " + issn);
    }
  }
  saveOutput();
}

function constructCSV(issn, data) {
  // code to get some data from the json in parameter "data"
  // ...
  // ...
  saveOutput() 
}

function saveOutput() {
  const csvContent = csvData.join("\n");
  fs.writeFileSync(output_file_dir, csvContent);
}

希望这有帮助:)。


0
投票

您没有向我们展示

text
如何填充数据,但由于您无法控制请求完成的顺序,因此您的代码可能会给出不可预测的结果。

您应该使用 promises 并行执行所有请求,并使用

Promise.all
来检测所有请求何时完成:

const requests = [];
for (let i = 0; i<issns.length; i++) {
  url = "some_api_url" + issns[i];
  requests.push(new Promise(function(resolve, reject) {
    https.get(url, (resp) => {
      ...
      resp.on('end', () => {
        data = JSON.parse(data);
        resolve(data);
      });
    }).on("error", (err) => {
      console.log("Error: " + err.message);
      reject(err);
    });
  }));
}
Promise.all(requests).then(function(csvData) {
  const csvContent = csvData.join("\n");
  fs.writeFileSync(output_file_dir, csvContent);
});

csvData
是一个数组,其中各个请求的
data
的顺序与您创建 承诺的顺序相同,无论它们解决的顺序如何。

© www.soinside.com 2019 - 2024. All rights reserved.