ChatGPT解决这个技术问题 Extra ChatGPT

“内容类型:应用程序/json;charset=utf-8”的真正含义是什么?

当我向我的 REST 服务发出带有 JSON 正文的 POST 请求时,我在消息头中包含 Content-type: application/json; charset=utf-8。如果没有此标头,我会从服务中收到错误消息。我也可以成功使用没有 ;charset=utf-8 部分的 Content-type: application/json

charset=utf-8 究竟是做什么的?我知道它指定了字符编码,但没有它服务可以正常工作。这种编码是否限制了消息正文中可以包含的字符?

有趣的是,根据 IANA's application/json Media Type Registration,似乎根本没有支持的 charset 参数,尽管在实践中经常提供。
I know it specifies the character encoding but the service works fine without it.“工作”并不总是意味着“现有代码/配置是涵盖所有极端情况以做一件事的最正确方式”。这取决于在其他情况下可能不起作用的所有约定和假设。就我个人而言,我总是尽可能地表达清楚。
发送“charset”参数是不正确且没有意义的。参见 RFC 8259,第 11 节,最后一句。
JSON必须用UTF-8编码,并且有没有“charset”参数。请参阅 this brief quote 或查看 RFC8259

d
deceze

标头只是表示内容的编码内容。不一定可以从内容本身推断出内容的类型,即您不一定只看内容就知道如何处理它。这就是 HTTP 标头的用途,它们告诉接收者他们(假设)正在处理什么样的内容。

Content-type: application/json; charset=utf-8 将内容指定为 JSON 格式,以 UTF-8 字符编码进行编码。指定编码对于 JSON 来说有些多余,因为 JSON 的默认(仅?)编码是 UTF-8。因此,在这种情况下,接收服务器显然很高兴知道它正在处理 JSON,并假设默认编码为 UTF-8,这就是它在有或没有标头的情况下工作的原因。

这种编码是否限制了消息正文中可以包含的字符?

不,您可以在标题和正文中发送任何您想要的内容。但是,如果两者不匹配,您可能会得到错误的结果。如果您在标头中指定内容是 UTF-8 编码的,但您实际上发送的是 Latin1 编码的内容,则接收器可能会产生垃圾数据,试图将 Latin1 编码的数据解释为 UTF-8。如果您当然指定要发送 Latin1 编码数据并且您实际上正在这样做,那么是的,您可以使用 Latin1 编码的 256 个字符。


当然,在 JSON 中,您仍然可以使用 \u20AC 等转义序列来表示非拉丁语字符。
根据 json 的标准,实际上不允许使用 latin1 对内容进行编码。 JSON 内容必须编码为 unicode,无论是 UTF-8、UTF-16 还是 UTF-32(大端或小端)。
application/json 上没有字符集参数。
@DanielLuna 是对的,application/json 必须采用其中一种 ucs 转换格式。此外,由于 JSON 的前四个字节是有限的,因此您始终可以判断它是 8、16 还是 32 以及它的字节序。
如果事件是多余的,出于安全原因,您可能希望包含 charset=utf-8github.com/shieldfy/API-Security-Checklist/issues/25
D
Drew Noakes

为了证实@deceze 声称默认 JSON 编码是 UTF-8...

IETF RFC4627

JSON 文本应以 Unicode 编码。默认编码为 UTF-8。由于 JSON 文本的前两个字符始终是 ASCII 字符 [RFC0020],因此可以确定八位字节流是 UTF-8、UTF-16(BE 或 LE)还是 UTF-32(BE 或 LE)通过查看前四个八位字节中的空值模式。 00 00 00 xx UTF-32BE 00 xx 00 xx UTF-16BE xx 00 00 00 UTF-32LE xx 00 xx 00 UTF-16LE xx xx xx xx UTF-8


将 JSON 视为二进制格式而不是文本格式总是有帮助的。
现在 RFC4627 已经被 RFC7159 淘汰了,它指出根值可能是一个字符串(与以前的规范形成鲜明对比),现在如何实现?该规范在这方面含糊不清,只是说允许使用三种编码,但没有说应该如何区分它们。
@FabioBeltramini 以上应该仍然成立,因为 JSON 中的字符串将不包含任何文字空字符(JSON 中的空值需要使用数字转义序列进行编码,即 "\u0000")。
实际上,UTF-16xx 中的第二个字符在这种情况下可能没有 NULL,但仍然可以从其他字节确定编码:xx 00 00 00 仍然是 UTF-32LE,xx 00 xx xx 仍然是 UTF-16LE,{ 3} 仍然是 UTF-16BE。
C
Community

请注意,IETF RFC4627 已被 IETF RFC7158 取代。在 [8.1] 节中,它撤回了@Drew 之前引用的文本,说:

实现不得在 JSON 文本的开头添加字节顺序标记。


尽管如此,这个假设仍然成立,因为任何有效的 json 仍然以两个 ascii 字符开头。
一个字符,因为单个数字是有效的 JSON 文件
RFC8259:实现不得在网络传输的 JSON 文本的开头添加字节顺序标记 (U+FEFF)。
r
roipeker

由于“charset=utf-8”,Dart http 的实现处理字节,所以我确信那里有几个实现支持这一点,以避免在从响应中读取字节时使用“latin-1”回退字符集。就我而言,我完全失去了响应正文字符串的格式,因此我必须手动将字节编码为 utf8,或者在我的服务器的 API 响应中添加该标头“内部”参数。


C
Calos

我正在使用 HttpClient 并返回内容类型为 application/json 的响应标头,由于 HttpClient 默认为 ISO-8859-1,因此我丢失了使用 unicode 的外语或符号等字符。因此,如@WesternGun 所述,尽可能明确以避免任何可能的问题。

由于服务器没有为我处理请求的标头字符集(method.setRequestHeader("accept-charset", "UTF-8");),因此无法处理,我不得不将响应数据作为绘制字节检索并使用 UTF-8 将其转换为字符串。因此,建议明确并避免假设默认值。


w
wscourge

我完全同意@deceze,但我想提出这个问题的“我从服务中得到一个错误”部分,

我们收到这种错误为 http 415

Http 415 不支持的媒体类型错误

HTTP 415 Unsupported Media Type 客户端错误响应代码表示服务器拒绝接受请求,因为负载格式是不受支持的格式。

格式问题可能是由于请求指示的 Content-Type 或 Content-Encoding,或者是直接检查数据的结果。

换句话说,这在 this example 中可见。

我们必须设置正确的内容类型,并且我们必须接受正确的内容类型,如 Add Content-Type: application/json 和 Accept: application/json。否则,它将假定为默认值


s
starriet

RFC 8259

IANA 注意事项 JSON 文本的媒体类型是 application/json。 ... 注意:没有为此注册定义“charset”参数。添加一个确实对合规收件人没有影响。

还,

8.1。在不属于封闭生态系统的系统之间交换的字符编码 JSON 文本必须使用 UTF-8 [RFC3629] 进行编码。以前的 JSON 规范没有要求在传输 JSON 文本时使用 UTF-8。然而,绝大多数基于 JSON 的软件实现都选择使用 UTF-8 编码,以至于它是唯一实现互操作性的编码。实现不得在网络传输的 JSON 文本的开头添加字节顺序标记 (U+FEFF)。为了互操作性,解析 JSON 文本的实现可能会忽略字节顺序标记的存在,而不是将其视为错误。

(强调我的)