【问题标题】::ERR_EMPTY_RESPONSE after two minutes timeout -axios-post - nodejs:ERR_EMPTY_RESPONSE 两分钟超时后 -axios-post - nodejs
【发布时间】:2020-08-07 20:02:20
【问题描述】:

我正在尝试在 nodejs / react 应用程序中上传文件。 文件的上传效果很好,但是当我想得到我的await.post() 请求的响应时,我遇到了一些问题。当我上传文件时,我制作了一个微调器来显示文件正在上传,我希望这个微调器在上传完成后停止,然后显示一条消息通知用户加载完成。

我解释了这些问题,因为它有点复杂。

当我在本地工作时:

两分钟后(我计时明白了),我的浏览器控制台显示错误消息net::ERR_EMPTY_RESPONSE。 但是在服务器端,一切都在继续,请求顺利结束。但是在前端,即使请求结束并且我的 post 请求正在向我的客户端发送 res 消息,我的微调器也不会停止转动。

我认为这是关于我的服务器超时的问题,所以我做了很多测试,将 setTimeout 放在我的服务器中:

var server = app.listen(PORT, () =>
  console.log(`Server started on port ${PORT}`)
);

server.timeout = 3840000;

而且在我的路线请求中:

router.post('/', async (req, res) => {
  req.setTimeout(3600000);

甚至我尝试在客户端更改我的axios.post 函数的超时时间:

const res = await axios.post('/api/students', newFile, {
      timeout: 3600000,
    });

但是没有什么能解决我的问题。

而奇怪的是,当托管应用程序时,问题就不一样了!

实际上没有错误消息,但 1 分钟后微调器无故停止。

我做了很多研究,但没有任何答案可以解决我的问题,我已经研究了几天,但我不明白为什么。我以为可能是代理问题或浏览器超时,但我不知道...

如果你有一个小小的领先优势,它可以帮助我很多!感谢您的帮助!

更新:

我的 /api/student 路由的代码

      const express = require('express');
const router = express.Router();
const fileUpload = require('express-fileupload');
const Student = require('../../models/Student');
const CSVToJSON = require('csvtojson');
const utf8 = require('utf8');
var accents = require('remove-accents');

const NodeGeocoder = require('node-geocoder');
const sleep = require('util').promisify(setTimeout);

let msg = 'Etudiants ajoutés à la base de données';

//The column that we want to keep in the database
const goodColumn = [
  'Civilite',
  'Nom_patronymique',
  'Prenom',
  'Date_naissance',
  'No_etudiant',
  'Libelle_nationalite',
  'Telephone_portable',
  'Mailum',
  'Adresse_fixe_postal',
  'Adresse_fixe_ville',
  'Libelle_etape',
];

// Set up the environnement for geocoding the adress
const options = {
  provider: 'openstreetmap',
};

const geoCoder = NodeGeocoder(options);

//FUNCTION TO VERIFY IF A STRING HAS A NUMBER IN IT
function hasNumber(myString) {
  return /\d/.test(myString);
}

router.post('/', (req, res, next) => {
  // This should be BEFORE `fileUpload`
  req.setTimeout(0);
  next();
});

router.use(fileUpload());

//@route   POST api/students
//@desc    Fill the database with the json information
//@access  Public
router.post('/', async (req, res, next) => {
  //FORMER FILES ROUTES
  //take the information
  const buf = Buffer.from(req.files.file.data).toString();

  //CONVERSION CSV STRING TO JSON
  CSVToJSON()
    .fromString(buf)
    .then((source) => {
      for (let i = 0; i < source.length; i++) {
        for (let j = 0; j < Object.keys(source[i]).length; j++) {
          const columnName = Object.keys(source[i]);
          columnName.forEach((element) => {
            if (!goodColumn.includes(element)) {
              delete source[i][element];
            }
            if (element == 'Libelle_etape') {
              const str = source[i]['Libelle_etape'];
              const result = accents.remove(utf8.decode(str));
              source[i]['Libelle_etape'] = result;
            }
          });
        }
      }
      data = JSON.stringify(source);
      datajson = JSON.parse(data);
      //USE THE FUNCTION TO PUT THE DATA IN THE DB
      insertIntoDataBase(datajson);
    });

  // CLEAR TABLE BEFORE ADD NEW STUDENTS FROM FILE
  Student.deleteMany({}, function (err) {});

  //ROUTES STUDENTS - FUNCTION  TO PUT THE JSON DATA IN THE DATABASE
  async function insertIntoDataBase(jsonString) {
    for (let i = 0; i < jsonString.length; i++) {
      console.log(`boucle ${i}`);

      try {
        //READ DATA FROM DE CSV FILE (already convert into json data) AND PUT IT INTO VARIABLES
        let {
          Civilite,
          Nom_patronymique,
          Prenom,
          Date_naissance,
          No_etudiant,
          Libelle_nationalite,
          Telephone_portable,
          Mailum,
          Adresse_fixe_postal,
          Adresse_fixe_ville,
          Libelle_etape,
        } = jsonString[i];
        console.log(Nom_patronymique + ' ' + Prenom);

        // VERIFICATION VILLE STRING FORMAT ( AVOIR NUMBER OR ..EME)
        if (hasNumber(Adresse_fixe_ville)) {
          Adresse_fixe_ville = Adresse_fixe_ville.replace(/[0-9]/g, '');
          if (Adresse_fixe_ville.endsWith(' EME')) {
            Adresse_fixe_ville = Adresse_fixe_ville.substring(
              0,
              Adresse_fixe_ville.length - 4
            );
          }
        }

        //VERIFICATION OF THE PHONE NUMBER - if empty attributes a default value
        if (Telephone_portable !== undefined && Telephone_portable.length < 1) {
          Telephone_portable = '0000000000';
        }

        // GEOCODING THE ADDRESS TO CONVERT INTO LATITUDE AND LONGITUDE

        geoCoder
          .geocode({
            city: Adresse_fixe_ville,
            zipcode: Adresse_fixe_postal,
          })
          .then(async (res) => {
            //TEST

            var Latitude;
            var Longitude;
            if (res[0] !== undefined) {
              Latitude = res[0].latitude;
              Longitude = res[0].longitude;
            } else {
              console.log(Adresse_fixe_ville);
              Latitude = 0.0;
              Longitude = 0.0;
            }

            //CREATE A STUDENT WITH THE INFO + LAT AND LONG
            student = new Student({
              Civilite,
              Nom_patronymique,
              Prenom,
              Date_naissance,
              No_etudiant,
              Libelle_nationalite,
              Telephone_portable,
              Mailum,
              Adresse_fixe_postal,
              Adresse_fixe_ville,
              Libelle_etape,
              Latitude,
              Longitude,
            });
            //VERIFICATION IF ALL THE ATTRIBUTE OF THE STUDENT ARE OK - IF NOT : undefined
            if (
              !(
                student.Civilite === undefined ||
                student.Nom_patronymique === undefined ||
                student.Prenom === undefined ||
                student.Date_naissance === undefined ||
                student.No_etudiant === undefined ||
                student.Libelle_nationalite === undefined ||
                student.Telephone_portable === undefined ||
                student.Mailum === undefined ||
                student.Adresse_fixe_postal === undefined ||
                student.Adresse_fixe_ville === undefined ||
                student.Libelle_etape === undefined
              )
            ) {
              //SAVE THE STUDENT IN THE DATABASE
              await student.save();
            } else {
              res.status(500);
              msg =
                'Le fichier csv téléchargé est au mauvais format de données';
            }
          })
          .catch((err) => {
            console.log(err);
          });
      } catch (err) {
        console.log(err.message);
        res.status(500);
        msg =
          'Erreur serveur, veuillez réessayer avec un fichier csv au bon format';
        return;
      }

      //WAIT FOR GEOCODER - 1,2 second
      await sleep(1200);
    }
    //COUNT A MANY STUDENT WE HAVE IN THE DATABASE
    Student.find().exec(function (err, results) {
      var count = results.length;
      res.json({ msg: msg, count: count });
    });
  }
});

//@route   GET api/students
//@desc    Return all the students in the database (all information / attributes)
//@access  Public
router.get('/', function (req, res, next) {
  Student.find(function (err, students) {
    if (err) {
      res.send(err);
    }
    res.json(students);
  });
});

module.exports = router;

【问题讨论】:

  • 请给/api/students提供路线。
  • @MarcosCasagrande 我将它添加到姿势的末尾,我将其全部放入以获取更多信息,但很多代码对问题无用
  • 你上传的文件有多大?
  • 这是一个巨大的文件,它是一个 1300 ligne 的 csv,上传大约需要 30 分钟...
  • 当我上传 csv 的轻量级版本时,需要不到 2 分钟,我没有问题,控制台中没有错误并且微调器停止

标签: node.js reactjs post axios timeout


【解决方案1】:

在节点 &lt; 13.0.0 中,默认套接字超时为 2 分钟,因此两分钟后套接字将关闭,并且您将在客户端获得 ERR_EMPTY_RESPONSE,因为套接字已关闭而不允许您响应请求。

从 Node 13.0.0 开始,默认超时设置为 0(无超时),这可能是您部署应用程序时它工作的原因,您的服务器可能正在运行 Node &gt;= 13.0.0

如果在使用req.setTimeout 的值大于2 分钟后,仍然存在该问题,可能是因为您没有正确结束请求,或者您在错误的地方使用了req.setTimeout

这是一个巨大的文件,它是一个 1300 法分的 csv,大约需要 30分钟上传

从您的评论中,我可以告诉您,您在路由中拥有的 req.setTimeout 没有做您想做的事情,因为在此之前您有一个中间件,可能是 multer 从您的代码中看到的没有设置req.setTimeout&gt;30 min

所以请求在到达您的路线之前就超时了。你应该这样做:

app.post(
    '/', 
    (req, res, next) => {
        // Set request setTimeout BEFORE any other middlewares
        req.setTimeout(ms('35m')); // using `ms` package
        next();
    },
    upload.single('file'), // or whatever multer setup you have
    (req, res, next) => {
        // Your route

    }
)

使用此代码,您有 35 分钟的时间上传并结束您的响应,因为它不会在 2 分钟后在 multer 中间件处超时。当然,如果您不知道需要多长时间(很可能是这种情况),您可以使用req.setTimeout(0) 或您认为合适的任何值。


更新

对于您的代码,您必须执行以下操作:

// or router.use((req, res, next) => ...)
router.post('/', (req, res, next) => {
   // This should be BEFORE `fileUpload`
   req.setTimeout(0);
   next();
});

router.use(fileUpload());

//@route   POST api/students
//@desc    Fill the database with the json information
//@access  Public
router.post('/', async (req, res, next) => {
   // ...rest of your code
})

【讨论】:

  • 我使用fileUpload() 来上传文件,我会试试你的回答非常感谢你,你认为它是这样的吗? ` router.post( '/', async (req, res, next) =&gt; { req.setTimeout(ms('35m')); next(); }, (req, res, next) =&gt; { //FORMER FILES ROUTES //take the information const buf = Buffer.from(req.files.file.data).toString(); //CONVERSION CSV STRING TO JSON [.....] 因为我在你的例子中没有像你这样的东西 uplaod.single(file)
  • 您缺少文件上传中间件,文件上传中间件必须在 *req.setTimeout` 之后,就像我的示例一样。
  • 我不确定我有没有像你说的那样上传中间件...这是这一行吗:router.use(fileUpload());
  • 不要在那里使用它。做我在请求中所说的: router.use((req, res, next) => req.setTimeout(0), fileUpload())
  • 那么您的快速设置中还有一些您没有显示的内容。因为使用 req.setTimeout 大于 2 分钟,你不会得到那个。尝试使用 curl
猜你喜欢
  • 2019-11-06
  • 2021-07-09
  • 2013-06-05
  • 1970-01-01
  • 1970-01-01
  • 2023-03-27
  • 1970-01-01
  • 2017-10-11
  • 2013-06-15
相关资源
最近更新 更多