Heroku crash over and over by POST request, multer

2019-06-26 07:30发布

My deployment on Heroku keep crashing on the POST request when I send the mulitpart form. I can't see in the logs if it's on the upload (multer) function, save (mongoose) function or sendMail (nodemailer) function. The only thing I see in the logs is a H18 error: Internal Server.

Router.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                 

3条回答
你好瞎i
2楼-- · 2019-06-26 08:02

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)
})
查看更多
Animai°情兽
3楼-- · 2019-06-26 08:11

I have realized that this error most times comes when one is trying to upload a large file, though heroku said "There is not a limit on filesize for uploads", your app probably got a large file that exceed the Heroku time bond for all requests on the Heroku platform must return the first byte within 30 seconds, it then resulted to the closing of the backend socket, belonging to your app’s web process before the backend returned an HTTP response.

But Heroku gave more reason why you might end up with that error, which I will advice you read for more clarification H18 - Server Request Interrupted

Resolution

The H18 error is similar to the H13 in that both signify that the socket was destroyed before a response was completed. With an H13, the socket was connected, then destroyed without sending any data. An H18 signifies that the socket connected, some data was sent as part of a response by the app, but then the socket was destroyed without completing the response.

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.

To find the error, first check your logs for stack traces near the H18. If you see none, you'll need to look more closely at the handlers for the specific request that's failing. Logging each step of the response, including the x-request-id header, can help.

The backend socket, belonging to your app’s web process was closed before the backend returned an HTTP response.

查看更多
我欲成王,谁敢阻挡
4楼-- · 2019-06-26 08:14

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                                                                     
查看更多
登录 后发表回答