当我向我的 REST 服务发出带有 JSON 正文的 POST 请求时,我在消息头中包含 Content-type: application/json; charset=utf-8
。如果没有此标头,我会从服务中收到错误消息。我也可以成功使用没有 ;charset=utf-8
部分的 Content-type: application/json
。
charset=utf-8
究竟是做什么的?我知道它指定了字符编码,但没有它服务可以正常工作。这种编码是否限制了消息正文中可以包含的字符?
application/json
Media Type Registration,似乎根本没有支持的 charset
参数,尽管在实践中经常提供。
I know it specifies the character encoding but the service works fine without it.
“工作”并不总是意味着“现有代码/配置是涵盖所有极端情况以做一件事的最正确方式”。这取决于在其他情况下可能不起作用的所有约定和假设。就我个人而言,我总是尽可能地表达清楚。
标头只是表示内容的编码内容。不一定可以从内容本身推断出内容的类型,即您不一定只看内容就知道如何处理它。这就是 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 个字符。
为了证实@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
"\u0000"
)。
xx 00 00 00
仍然是 UTF-32LE,xx 00 xx xx
仍然是 UTF-16LE,{ 3} 仍然是 UTF-16BE。
请注意,IETF RFC4627 已被 IETF RFC7158 取代。在 [8.1] 节中,它撤回了@Drew 之前引用的文本,说:
实现不得在 JSON 文本的开头添加字节顺序标记。
由于“charset=utf-8”,Dart http 的实现处理字节,所以我确信那里有几个实现支持这一点,以避免在从响应中读取字节时使用“latin-1”回退字符集。就我而言,我完全失去了响应正文字符串的格式,因此我必须手动将字节编码为 utf8,或者在我的服务器的 API 响应中添加该标头“内部”参数。
我正在使用 HttpClient 并返回内容类型为 application/json
的响应标头,由于 HttpClient 默认为 ISO-8859-1,因此我丢失了使用 unicode 的外语或符号等字符。因此,如@WesternGun 所述,尽可能明确以避免任何可能的问题。
由于服务器没有为我处理请求的标头字符集(method.setRequestHeader("accept-charset", "UTF-8");
),因此无法处理,我不得不将响应数据作为绘制字节检索并使用 UTF-8 将其转换为字符串。因此,建议明确并避免假设默认值。
我完全同意@deceze,但我想提出这个问题的“我从服务中得到一个错误”部分,
我们收到这种错误为 http 415
Http 415 不支持的媒体类型错误
HTTP 415 Unsupported Media Type 客户端错误响应代码表示服务器拒绝接受请求,因为负载格式是不受支持的格式。
格式问题可能是由于请求指示的 Content-Type 或 Content-Encoding,或者是直接检查数据的结果。
换句话说,这在 this example 中可见。
我们必须设置正确的内容类型,并且我们必须接受正确的内容类型,如 Add Content-Type: application/json 和 Accept: application/json。否则,它将假定为默认值
IANA 注意事项 JSON 文本的媒体类型是 application/json。 ... 注意:没有为此注册定义“charset”参数。添加一个确实对合规收件人没有影响。
还,
8.1。在不属于封闭生态系统的系统之间交换的字符编码 JSON 文本必须使用 UTF-8 [RFC3629] 进行编码。以前的 JSON 规范没有要求在传输 JSON 文本时使用 UTF-8。然而,绝大多数基于 JSON 的软件实现都选择使用 UTF-8 编码,以至于它是唯一实现互操作性的编码。实现不得在网络传输的 JSON 文本的开头添加字节顺序标记 (U+FEFF)。为了互操作性,解析 JSON 文本的实现可能会忽略字节顺序标记的存在,而不是将其视为错误。
(强调我的)
不定期副业成功案例分享
\u20AC
等转义序列来表示非拉丁语字符。application/json
必须采用其中一种 ucs 转换格式。此外,由于 JSON 的前四个字节是有限的,因此您始终可以判断它是 8、16 还是 32 以及它的字节序。charset=utf-8
:github.com/shieldfy/API-Security-Checklist/issues/25