Node.js Heroku通过POST请求一次又一次崩溃,multer或NodeEmailer H=18

Node.js Heroku通过POST请求一次又一次崩溃,multer或NodeEmailer H=18,node.js,heroku,deployment,multer,nodemailer,Node.js,Heroku,Deployment,Multer,Nodemailer,当我发送多部分表单时,我在Heroku上的部署在POST请求上不断崩溃。我在日志中看不到它是在上传(multer)功能、保存(mongoose)功能还是发送邮件(nodemailer)功能上。 我在日志中唯一看到的是H18错误:内部服务器 路由器.js const express = require("express"); const mongoose = require("mongoose"); const router = express.Router(); const multer = r

当我发送多部分表单时,我在Heroku上的部署在POST请求上不断崩溃。我在日志中看不到它是在上传(multer)功能、保存(mongoose)功能还是发送邮件(nodemailer)功能上。 我在日志中唯一看到的是H18错误:内部服务器

路由器.js

const express = require("express");
const mongoose = require("mongoose");
const router = express.Router();
const multer = require("multer");
const path = require("path");
const File = require("../models/Files");
const mail = require("../handlers/mailer");

// Set storage engine
const storage = multer.memoryStorage();

// Init upload
const upload = multer({
  storage: storage
}).single("file");

router.get("/", (req, res) => {
  res.render("index");
});

router.post("/send", async (req, res, next) => {

  await upload(req, res, async err => {
    if (err) {
      console.log("error by uploading file:", err);
    } else {
      console.log(`File is uploaded to the memoryStorage: ${req.file.originalname} `);
    }

    // Create a model to save in the database
    const fileUpload = new File({
      fromEmail: "<dk@bigbrother.nl>",
      fromName: '"Dennis Klarenbeek The heroku H18 error is thrown when the socket was destroyed before a response is completed. From heroku docs it states:

Usually, an H18 indicates that a response has multiple stages - for instance, streaming chunks of a large response - and that one of those stages has thrown an error."

https://help.heroku.com/18NDWDW0/debugging-h18-server-request-interrupted-errors-in-nodejs-applications

There are some steps we can do to refactor the code so we use multer as a middleware and to improve the error handling so we can see where the error actually occurs.

To catch errors thrown when resolving an await, you need to wrap it around a
try...catch 
block. It works exactly like the Promise.catch.

const express = require("express");
const mongoose = require("mongoose");
const router = express.Router();
const multer = require("multer");
const path = require("path");
const File = require("../models/Files");
const mail = require("../handlers/mailer");

// Set storage engine
const storage = multer.memoryStorage();

// Init upload
const upload = multer({
  storage: storage
}).single("file");

router.get("/", (req, res) => {
  res.render("index");
});

router.post("/send", async (req, res, next) => {

  // No need to await  this middleware
  upload(req, res, err => {
    // Refactor to using recommended multer error handling
    // https://github.com/expressjs/multer#error-handling
    if (err instanceof multer.MulterError) {
      // A Multer error occurred when uploading.
      console.log("multer error when uploading file:", err);
      return res.sendStatus(500);
    } else if (err) {
      // An unknown error occurred when uploading.
      console.log("unknown error when uploading file:", err);
      return res.sendStatus(500);
    }

    console.log(`File is uploaded to the memoryStorage: ${req.file.originalname} `);

    // Create a model to save in the database
    const fileUpload = new File({
      fromEmail: "<dk@bigbrother.nl>",
      fromName: '"Dennis Klarenbeek Catch all uncaught exceptions in nodejs to get a better idea where things break.

Add this lines into your nodejs file

process.on('uncaughtException', function (err) {
  console.error(err.stack); // either logs on console or send to other server via api call.
  process.exit(1)
})
const express=require(“express”);
const mongoose=需要(“mongoose”);
const router=express.router();
const multer=要求(“multer”);
常量路径=要求(“路径”);
const File=require(“../models/Files”);
const mail=require(“../handlers/mailer”);
//设置存储引擎
const storage=multer.memoryStorage();
//初始化上载
const upload=multer({
存储:存储
}).单一(“文件”);
路由器.get(“/”,(请求,res)=>{
res.render(“索引”);
});
路由器.post(“/send”),异步(请求、恢复、下一步)=>{
等待上载(请求、恢复、异步错误=>{
如果(错误){
log(“上传文件时出错:”,err);
}否则{
log(`File上载到memoryStorage:${req.File.originalname}`);
}
//创建要保存在数据库中的模型
const fileUpload=新文件({
来自电子邮件:“”,

fromName:“”Dennis Klarenbeek在响应完成之前销毁套接字时,会引发heroku H18错误。在heroku文档中,它声明:

通常,H18表示响应有多个阶段-例如 例如,流式传输大量响应的数据块,以及其中的一个 stages抛出了一个错误。“

我们可以执行一些步骤来重构代码,以便将multer用作中间件,并改进错误处理,以便我们可以看到错误实际发生的位置

要捕获解析等待时抛出的错误,您需要将其包装在
try…catch
块中。它的工作原理与Promise.catch完全相同

const express=require(“express”);
const mongoose=需要(“mongoose”);
const router=express.router();
const multer=要求(“multer”);
常量路径=要求(“路径”);
const File=require(“../models/Files”);
const mail=require(“../handlers/mailer”);
//设置存储引擎
const storage=multer.memoryStorage();
//初始化上载
const upload=multer({
存储:存储
}).单一(“文件”);
路由器.get(“/”,(请求,res)=>{
res.render(“索引”);
});
路由器.post(“/send”),异步(请求、恢复、下一步)=>{
//无需等待此中间件
上传(请求、回复、错误=>{
//使用推荐的multer错误处理进行重构
// https://github.com/expressjs/multer#error-处理
if(错误实例为multer.MulterError){
//上载时发生Multer错误。
log(“上传文件时出现multer错误:”,err);
返回res.sendStatus(500);
}否则如果(错误){
//上载时发生未知错误。
log(“上载文件时出现未知错误:”,错误);
返回res.sendStatus(500);
}
log(`File上载到memoryStorage:${req.File.originalname}`);
//创建要保存在数据库中的模型
const fileUpload=新文件({
来自电子邮件:“”,

fromName:“”Dennis Klarenbeek捕获nodejs中所有未捕获的异常,以便更好地了解哪里出了问题

将这些行添加到nodejs文件中


我已经意识到,当一个人试图上传一个大文件时,大多数时候都会出现这个错误,尽管heroku说“上传的文件大小没有限制“,您的应用程序可能得到了一个超过Heroku时间限制的大文件,因为Heroku平台上的所有请求必须在30秒内返回第一个字节,然后导致后端套接字关闭,在后端返回HTTP响应之前,属于您应用程序的web进程

但Heroku给出了更多的理由,说明了为什么你最终可能会犯这个错误,我建议你阅读更多的解释

决议 H18错误与H13类似,都表示 套接字在响应完成之前被销毁。使用H13时 套接字已连接,然后在不发送任何数据的情况下被销毁。H18 表示套接字已连接,某些数据已作为连接的一部分发送 应用程序的响应,但随后套接字被销毁,而没有 完成回答

通常,H18表示响应有多个阶段-例如 例如,流式传输大量响应的数据块,以及其中的一个 stages抛出了一个错误

要查找错误,请首先检查日志中靠近 H18.如果你什么也看不到,你需要更仔细地观察操纵器 对于失败的特定请求。记录 响应,包括x-request-id头,可以提供帮助

属于应用程序web进程的后端套接字已关闭 在后端返回HTTP响应之前


您使用的是
wait
(承诺)的组合还有我不熟悉的回调..我在
multer
中没有看到任何对承诺的引用,你确定你用对了吗?当你在本地运行它时,你有没有收到任何错误?如果你在本地运行它,这会抛出一个错误
res。redirect
将首先尝试执行,这将导致
在它们运行后无法设置头重新发送到客户端
在对
res
执行任何操作之前,您应该考虑重构请求必须处理的内容,然后在最终承诺范围内进行响应,并使用
下一次
回调捕获错误。您应该在异步调用中使用承诺,在同步代码中尝试捕获。根据官方文档try-catch仅适用于同步代码。由于节点平台主要是异步的(特别是在生产环境中),try-catch不会捕获很多异常@Sohail,原来的问题是使用async/await,这只是处理承诺的特殊语法。要捕获async/await期间抛出的异常,您可以将其包装为try/catch(签出)。express的官方文档也引用