如何让 koa ctx.throw() 使用 application/json 而不是 text/plain

How to make koa ctx.throw() use application/json rather than text/plain

我为我的 koa 应用程序制作了一个自定义错误处理程序,它运行良好(除了一个症结点)- 使用 ctx.throw() 意味着任何堆栈跟踪都会发送到服务器日志,并且还会发送任何自定义错误消息在回复中。

一个问题是Content-Typeheader是text/plain,但我真的需要它是application/json

app.js:

import Koa from 'koa';
import bodyParser from 'koa-bodyparser';
import logger from 'koa-morgan';

import authentication from './middleware/authentication';
import config from './config';
import errorHandler from './middleware/error-handler';
import notificationsRoutes from './routes/notifications';

const app = new Koa();

app.use(errorHandler);
app.use(bodyParser());
app.use(logger(config.logLevel));
app.use(authentication);
app.use(notificationsRoutes.routes());

export default app;

error-handler.js:

export default async (ctx, next) => {
  return next().catch(({ statusCode, message }) => {
    ctx.throw(statusCode, JSON.stringify({ message }));
  });
};

(我认为 (statusCode, JSON.stringify({ message })); 可能会将响应强制转换为 application/json 但事实并非如此。

我用谷歌搜索无果。请帮忙!

设法修改 error-handler 以产生所需的结果。工作得很好 - 堆栈跟踪被发送到服务器日志并且该消息的第一行成为响应正文中的 message 。后者可能被某些人认为是缺点,但这取决于您的追求。

error-handler.js:

export default async (ctx, next) => {
  return next().catch(err => {
    const { statusCode, message } = err;

    ctx.type = 'json';
    ctx.status = statusCode || 500;
    ctx.body = {
      status: 'error',
      message
    };

    ctx.app.emit('error', err, ctx);
  });
};

找到这个并用作参考:https://github.com/koajs/examples/blob/master/errors/app.js

值得一提的是,这个自定义错误 - ServerError.js - 在应用程序中使用;这就是为什么 ctx.status = statusCode || 500 - statusCode 在使用时由 ServerError 提供,但对于抛出的非自定义错误,statusCode 会通过 error-handler.js 作为 undefined 所以需要 || 500

ServerError.js:

export class ServerError extends Error {
  constructor(statusCode, message) {
    super(message);
    this.statusCode = statusCode;
  }
}

(用法:throw new ServerError(400, 'my informative error message');

在你的任何中间件中都没有任何 catch 块,错误将一直传播到 app.js 中的顶部 errorHandler 中间件(这就是你想要发生)。

koa 中的自定义错误处理似乎产生了许多不同的意见,但目前看来这对我们来说效果很好。

添加错误处理程序中间件

  server.use(async function jsonErrorHandler(ctx, next)  {
    try {
      await next();
    } catch (err: any) {
      ctx.status = err.status || err.statusCode || 500;
      ctx.body = { message: err };
      ctx.app.emit('error', err, ctx);
    }
  });

然后像这样抛出错误:

export async function usersIssuesHandler(context: Context) {
    ....
    context.throw('some error here',500);
}