Node.js Heroku通过POST请求一次又一次崩溃,multer或NodeEmailer H=18
当我发送多部分表单时,我在Heroku上的部署在POST请求上不断崩溃。我在日志中看不到它是在上传(multer)功能、保存(mongoose)功能还是发送邮件(nodemailer)功能上。 我在日志中唯一看到的是H18错误:内部服务器 路由器.jsNode.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
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的官方文档也引用