在使用nodejs和express构建REST API时,设置响应状态和JSON内容的正确方法是什么?

233

我正在使用Nodejs和Express构建一个小型rest API,研究其中的玩法。我的问题是,在设置代码状态以及响应数据方面,有哪些好的实践/最佳方式?

让我用一点代码来解释一下(我不会放置启动服务器所必需的node和express代码,只放置与路由器方法相关的代码):

router.get('/users/:id', function(req, res, next) {
  var user = users.getUserById(req.params.id);
  res.json(user);
});


exports.getUserById = function(id) {
  for (var i = 0; i < users.length; i++) {
    if (users[i].id == id) return users[i];
  }
};
以下代码可以完美运行,使用Postman发送请求时,我会得到以下结果: enter image description here 如您所见,状态显示为200,这是正常的。但是,这是最好的方法吗?是否存在情况,我需要自己设置状态以及返回的JSON?还是这总是由express处理?
例如,我刚刚进行了一个快速测试,并略微修改了上面的get方法:
router.get('/users/:id', function(req, res, next) {
  var user = users.getUserById(req.params.id);
  if (user == null || user == 'undefined') {
    res.status(404);
  }
  res.json(user);
});

如您所见,如果在数组中未找到用户,我将仅设置状态码为404。

欢迎提供有关此主题的更多资源/建议以便深入学习。


3
这是我最受欢迎的回答,但它并没有被采纳 :( @dukable,我知道这已经过了一段时间了,但是你的问题解决了吗? - Michał Dudak
@MichałDudak:是的,你的回答应该被接受。但是这个可压缩的用户自2015年10月15日以来就不活跃了(截至2017年7月31日)。无论如何,给你的回答+1 ;) - Amol M Kulkarni
13个回答

293

Express API参考文档中涵盖了这种情况。

请查看状态码(status)发送(send)

简而言之,您只需在调用jsonsend之前调用status方法:

res.status(500).send({ error: "boo:(" });

3
似乎这个方法已经失效了。响应的状态码是正确的,但没有正文。 - LondonRob
3
忽略我上一个评论。如果您将状态设置为204 (无内容),它将不会发送正文。 - LondonRob
5
res.sendStatus(400);的意思是向客户端发送一个状态码为400的响应,表示“错误请求”。而且,此方法可以用于快速地仅仅发送一个状态码,它等同于res.status(400).send('Not Found'),即向客户端发送一个状态码为400的响应,并带有一个字符串数据"Not Found"。 - Davide

86
你可以这样做:
res.status(400).json(json_response);

这将把HTTP状态码设置为400,在Express 4中也适用。


24
“express deprecated res.json(status, obj): Use res.status(status).json(obj) instead” 的意思是:“express不再推荐使用res.json(status, obj),请改为使用res.status(status).json(obj)”。因此,现在可以使用“res.status(400).json(json_response)”来实现此功能。 - Will Luce
是的,谢谢...它被标记为已弃用,但仍然可以工作 :P 你的评论是有效的,很好的观点。 - mzalazar
1
支持答案 - res.status(500).send({ error: "boo:(" }); - prayagupa

47

当使用res.sendres.json等方法时,默认的状态码为200。

您可以像这样设置状态码:res.status(500).json({ error: 'something is wrong' });

通常我会做类似于以下的操作…

router.get('/something', function(req, res, next) {
  // Some stuff here
  if(err) {
    res.status(500);
    return next(err);
  }
  // More stuff here
});

然后让我的错误中间件发送响应,并在出现错误时执行任何其他需要的操作。

另外:自版本4.9.0起,res.sendStatus(status)已添加。 http://expressjs.com/4x/api.html#res.sendStatus


29

一个HTTP状态码列表

响应状态的最佳实践是根据错误类型发送正确的HTTP状态码(客户端错误为4xx,服务器错误为5xx)。关于实际的JSON响应,没有一本“圣经”,但一个好的想法是在成功响应的根对象中再次将状态和数据作为2个不同的属性发送(这样你可以让客户端从HTTP头和负载本身中捕获状态),并在出现错误的情况下通过第3个属性以人能理解的方式来解释错误。

Stripe的 API 在现实世界中的行为类似。

OK

200, {status: 200, data: [...]}

错误

400, {status: 400, data: null, message: "You must send foo and bar to baz..."}

14

我正在我的Express.js应用程序中使用这个:

app.get('/', function (req, res) {
    res.status(200).json({
        message: 'Welcome to the project-name api'
    });
});

8

获取包含以下属性的完整HttpResponse的标准方法:

  1. body // 包含您的数据
  2. headers // 响应头信息
  3. ok // 指示响应是否成功的布尔值
  4. status // 响应状态码
  5. statusText // 响应状态消息
  6. type // 响应类型
  7. url // 请求的URL

在后端实现时,请执行以下操作:

router.post('/signup', (req, res, next) => {
    // res object have its own statusMessage property so utilize this
    res.statusText = 'Your have signed-up succesfully'
    return res.status(200).send('You are doing a great job')
})

在前端,例如在Angular中,只需执行以下操作:

let url = `http://example.com/signup`
this.http.post(url, { profile: data }, {
    observe: 'response' // remember to add this, you'll get pure HttpResponse
}).subscribe(response => {
    console.log(response)
})

我遇到了一个错误,无法将值分配给statusText,因为它是一个只读属性。 - Victor Eke

4
res.status(500).jsonp(dataRes);

4
try {
  var data = {foo: "bar"};
  res.json(JSON.stringify(data));
}
catch (e) {
  res.status(500).json(JSON.stringify(e));
}

3

发送错误响应的最佳方式是 return res.status(400).send({ message: '发生了一个错误' })

然后,在您的前端代码中,您可以使用类似以下的代码来捕获它:

        url: your_url,
        method: 'POST',
        headers: headers,
        data: JSON.stringify(body),
    })
        .then((res) => {
            console.log('success', res);
        })
        .catch((err) => {
            err.response && err.response.data && this.setState({ apiResponse: err.response.data })
        })

仅仅记录err不起作用,因为你发送的消息对象位于err.response.data中。

希望这有所帮助!


2
你可以这样做。
            return res.status(201).json({
                statusCode: req.statusCode,
                method: req.method,
                message: 'Question has been added'
            });

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接