Node.js在处理Express中的错误时为何会出现“Headers already sent”错误。

huangapple go评论79阅读模式
英文:

Why Node.js crashes with Headers already sent Error when handling errors in Express

问题

我使用Express创建一个用于用户注册的API端点。问题是,每当我发送一个请求来触发API端点的错误时,我的Node.js服务器就会崩溃,并显示以下消息:

node:internal/errors:491
[1]     ErrorCaptureStackTrace(err);
[1]     ^
[1]
[1] Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent 
to the client
[1]     at new NodeError (node:internal/errors:400:5)
[1]     at ServerResponse.setHeader (node:_http_outgoing:663:11)
[1]     at ServerResponse.header (D:\...\node_modules\express\lib\response.js:794:10)
[1]     at ServerResponse.send (D:\...\node_modul

所以,每当发送错误(失败)响应时,Node.js服务器都会崩溃,但当发送成功响应时,它不会崩溃。所以我猜我在处理错误时出了问题?

我在这里做错了什么?以下是我的实现:

const registerUser = async (req: Request, res: Response) => {
  try {
    const userData = createUserSchema.parse(req.body) as User;

    const salt = await bcrypt.genSalt(10);
    const hashedPassword = await bcrypt.hash(userData.password, salt);

    const user = await db.user.create({
      data: {
        ...userData,
        password: hashedPassword,
      },
    });

    return res.status(201).json({
      status: 'success',
      data: { name: user.name, email: user.email },
    });
  } catch (error) {
    if (error instanceof z.ZodError) {
      return res.status(422).json({
        status: 'fail',
        message: error.issues,
      });
    } else if (error instanceof Prisma.PrismaClientKnownRequestError) {
      if (error.code === 'P2002') {
        return res.status(409).json({
          status: 'fail',
          message: 'Email address is already in use',
        });
      }
    }

    return res.status(500).json({
      status: 'fail',
      message: 'Something went wrong',
    });
  }
};
英文:

I'm using Express to create an API endpoint for user registration. The problem is, whenever I send a request that will initiate an error to that API endpoint, my node.js server crashes and gives me the following message:

node:internal/errors:491
[1]     ErrorCaptureStackTrace(err);
[1]     ^
[1]
[1] Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent 
to the client
[1]     at new NodeError (node:internal/errors:400:5)
[1]     at ServerResponse.setHeader (node:_http_outgoing:663:11)
[1]     at ServerResponse.header (D:\...\node_modules\express\lib\response.js:794:10)
[1]     at ServerResponse.send (D:\...\node_modul

So, the node.js server crashes whenever is sending an error (fail) response, but when it's sending success response it doesn't crash. So I guess I'm not handling errors proper here?

What I'm doing wrong here? Here is my implementation:

const registerUser = async (req: Request, res: Response) => {
  try {
    const userData = createUserSchema.parse(req.body) as User;

    const salt = await bcrypt.genSalt(10);
    const hashedPassword = await bcrypt.hash(userData.password, salt);

    const user = await db.user.create({
      data: {
        ...userData,
        password: hashedPassword,
      },
    });

    return res.status(201).json({
      status: 'success',
      data: { name: user.name, email: user.email },
    });
  } catch (error) {
    if (error instanceof z.ZodError) {
      return res.status(422).json({
        status: 'fail',
        message: error.issues,
      });
    } else if (error instanceof Prisma.PrismaClientKnownRequestError) {
      if (error.code === 'P2002') {
        return res.status(409).json({
          status: 'fail',
          message: 'Email address is already in use',
        });
      }
    }

    return res.status(500).json({
      status: 'fail',
      message: 'Something went wrong',
    });
  }
};

I've tried to return error only for one case to see if these responses are conflicting but even if I have only one response, node.js server crashes.

答案1

得分: 1

这个错误是因为您尝试在响应头已经发送给客户端之后设置响应头。在Express中,在发送响应正文部分后,您不能再设置响应头。当您尝试在已经发送响应正文部分或成功响应后发送错误(失败)响应时,就会出现这个错误。

要解决这个问题,请确保在您的代码中适当地处理错误。确保您不会为单个请求向客户端发送多个响应。您可以使用Express错误处理中间件捕获错误并向客户端发送适当的响应,而不会引发"ERR_HTTP_HEADERS_SENT"错误。

尝试使用类似以下的中间件:

app.use((err, req, res, next) => {
    console.error(err);

    res.status(500).json({
     status: 'fail',
     message: '出现了问题',
    });
});

使用Express中间件将节省您大量的工作。

https://expressjs.com/en/guide/using-middleware.html

英文:

This error occurs because you are trying to set the response headers after they have already been sent to the client. In Express, you cannot set response headers after sending a response body part. This error occurs when you try to send an error (fail) response after you have already sent a response body part or a success response.

To fix this, make sure you're handling errors appropriately in your code. Make sure you don't send more than one response to the client for a single request. You can use the Express Error Handling Middleware to catch errors and send an appropriate response to the client without throwing an "ERR_HTTP_HEADERS_SENT" error.

Try with middleware like this:

app.use((err, req, res, next) => {
console.error(err);
res.status(500).json({
status: 'fail',
message: 'Something went wrong',
});
});

https://expressjs.com/en/guide/using-middleware.html

Using express middlware will save you a lot of effort

huangapple
  • 本文由 发表于 2023年5月29日 21:52:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/76357940.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定