Koa的`ctx.status`没有被发送给客户

时间:2017-05-18 05:04:23

标签: javascript node.js http fetch koa

这是我的简单路线:

router.post('/getFile', async (ctx) => {
  const fileName = `${ctx.request.body.file}.pdf`;
  const file = fs.createReadStream(fileName); // This file might not exist.

  file.on('error', (err) => {
    ctx.response.status = 500; // This status code doesn't make it to client when there's an error.
  });

  ctx.response.type = 'application/pdf';
  ctx.response.body = file;
});

这是我的客户代码:

async function main() {
  const request = {
    method: 'POST',
    body: JSON.stringify({ file: 'bad-file-name' }),
    headers: {
      'Content-Type': 'application/json',
      'Accept': 'application/pdf'
    }
  };

  const response = await fetch('/getFile', request);

  if (!response.ok) {
    console.log(response.status); // This is always 404 when I give a bad file name, even though I set it to 500 above. Why?
  }
}

当我发送正确的文件名时,一切都很好,但为什么响应状态代码总是404,即使我在错误期间在服务器代码中将其设置为500?可能是在我的代码到达ctx.response.body = ...之前响应已经完成发送,在这种情况下.on('error')中的代码没有做任何事情吗?

任何帮助都将不胜感激。

2 个答案:

答案 0 :(得分:4)

查看at the Koa code,它具有ENOENT的特定处理(这是在文件不存在时引发的错误):

// ENOENT support
if ('ENOENT' == err.code) err.status = 404;

从我所看到的,您无法更改Koa将发回的状态代码(并且公平地说,为不存在的文件发回404 有意义)

然而,这是一个快速入侵:因为Koa明确检查err.code匹配ENOENT,如果您更改了该代码,您可以欺骗Koa返回另一个状态代码:

file.on('error', err => {
  err.code   = 'ENOEXIST'; // a made-up code
  err.status = 500;
});

或者,您可以先检查(使用fs.exists()fs.access()fs.stat()),然后在创建读取流之前查看该文件是否存在。

答案 1 :(得分:0)

我认为你需要尝试这样的事情:

router.post('/getFile', async (ctx) => {
  const fileName = `${ctx.request.body.file}.pdf`;
  const file = fs.createReadStream(fileName); // This file might not exist.

  file.on('error', (err) => {
    ctx.response.status = 500; // This status code doesn't make it to client when there's an error.
  });

  file.on('close', () => {
    ctx.response.type = 'application/pdf';
    ctx.response.body = file;
  });
});