Node.js / Express - 如何设置响应字符编码?

28

假设我有:

app.get('/json', function(req, res) {
    res.set({
        'content-type': 'application/json'
    }).send('{"status": "0"}');
});

我试图使用以下方式将响应发送为UTF-8,但没有成功:

app.get('/json', function(req, res) {
    // From Node.js Official Doc
    // http://nodejs.org/api/http.html#http_http_request_options_callback
    res.setEncoding('utf8');

    res.set({
        'content-type': 'application/json'
    }).send('{"status": "0"}');
});

在Express中设置字符编码的正确方法是什么?


4
使用 res.json({"status": "0"}); 有什么问题? - mkoryak
1
因为我不知道它 - 谢谢! - gsklee
先阅读文档,再编写代码 ;) - mkoryak
1
提醒:在你开始修复之前,请确保它是坏的,即,在使用.set设置值之前,请验证响应中获取到的头数据。 - Ronnie Royston
5个回答

37

如果你发现 Express 没有自动设置字符集,那么你可能需要在 content-type 字符串的末尾明确添加一个字符集:

 res.set({ 'content-type': 'application/json; charset=utf-8' });

字符集并不总是自动设置必须手动设置才能在所有浏览器和ajax库中正常工作,否则可能会遇到编码错误。

特别是在 Express 4.x 中,我发现当你调用 res.json(someObject) 返回某个对象时,它通常会自动返回带有 content-type: application/json; charset=utf-8 的内容类型,但并不总是这样。

当在某些对象上调用 res.json() 时,它可能会返回不带字符集编码的 content-type: application/json(即没有字符集编码!)。 我实际上不确定是什么会触发这种情况,除了它与返回的特定对象有关。

我之所以注意到这一点,是因为自动化测试明确检查了响应头,并发现某些响应缺少字符集声明(即使内容类型仍然是 application/json)。


3
"charset" 应仅用于文本/ * 类型的资源。 "application/json" 标准上默认使用 UTF-8 编码,因此无需进行指定。 - Rich Remer
1
根据RFC,application/json应始终为UTF(默认为UTF-8),不应具有charset属性,但实际上,如果您不设置它,许多使用者将破坏结果(包括某些浏览器),这就是为什么这是一种常见模式的原因。 - Iain Collins
2
即使有些客户端无法处理它,您也会给符合标准的客户端引入问题,因为它们不应该期望从“应用程序/*”媒体类型中剥离字符集。最好停止使用不可靠的客户端,而不是破坏所有正常工作的客户端。 - Rich Remer
2
@RichRemer添加这些信息不会对确认客户造成问题。这在RFC 7159中明确说明(并在上面链接的答案中引用)。 - Iain Collins
你可以尝试使用 res.set({ 'content-type': 'application/json' }); 去除字符集,但是即使你没有发送 JSON 数据,expressjs 仍会再次添加它。 - Marc

14

使用res.charset:http://expressjs.com/api.html#res.charset

res.charset = 'value';
res.send('some html');
// => Content-Type: text/html; charset=value

然而,默认情况下,JSON是UTF-8编码的,因此您不需要设置任何内容。


3
这在 Express 4 中有所变化。请参考此处:https://github.com/visionmedia/express/wiki/Migrating%20from%203.x%20to%204.x#rescharset - Deiwin
2
当你在文本形式下查看JSON时,Web浏览器不一定会将其解释为UTF-8。在调试应用程序时可能会非常混乱和困惑。设置res.charSet仍然是个好主意。 - cleong
1
同意@Deiwin的观点。必须指定字符集。否则默认不会被解释为UTF-8。在我的情况下解决了我的问题。 - Saeger

3

这对我起了作用。

res.writeHead(200, {'Content-Type': 'text/html; charset=utf-8'});

我的意思是对我来说是HTML,确保你在你的情况下使用JSON作为内容类型! - Siva
我在没有使用Express的情况下使用了Node,所以这对我来说完美地运行了。 - Saurabh Misra

1

我遇到了类似的问题,我从数据库中收集瑞典字符并将它们输出为JSON对象。当来自数据库的字符不是UTF-8时,节点实际上并不关心json是否必须是UTF-8。因此,假设“你不需要设置任何东西”是错误的。这取决于您使用的字符集。


不是真正的答案,而是对@dankohn答案的评论。 - robertklep

1

在手动设置标头参数之前,请检查您的服务器默认情况下发送了什么。在我的情况下,我正在使用“无服务器”云提供的Node.js实例。显然,这些通常是由NGINX前端处理的,我假设这是基于默认设置设置某些内容。...我根本不需要设置 res.set 。当然,我正在返回HTML,...只是提醒一下 - 在修复之前,请确保它已经出了故障。

accept-ranges: bytes
accept-ranges: bytes
cache-control: private
content-encoding: gzip
content-type: text/html; charset=utf-8
date: Fri, 21 Dec 2018 21:40:37 GMT
etag: W/"83-xwilN/BBLLLAAAHHH/0NBLAH0U"
function-execution-id: 5thvkjd4wwru
server: nginx
status: 200
vary: accept-encoding, cookie, authorization
via: 1.1 varnish
x-cache: MISS
x-cache-hits: 0
x-cloud-trace-context: 18c611BBBBLLLLAAAHHH9594d9;o=1
x-powered-by: Express
x-served-by: cache-dfw18631-DFW
x-timer: S15BBLLLAAHHH.913934,VS0,VE3404 

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