2

我们有一个通过 HTTP 公开的 RESTful API,它以自然的方式利用 HTTP 状态行(状态代码和原因短语)将 API 结果传达给客户端(http://www.w3.org/Protocols/ rfc2616/rfc2616-sec6.html)。

例如,我们有以下并发错误的状态行:

HTTP/1.1 409 资源由其他用户更新。重新加载并重试。

最近事实证明,这些消息将呈现给针对我们的 API 构建的应用程序的最终用户,这意味着我们需要对它们进行本地化。我想知道在这种情况下这是否是一种可接受的方法,特别是考虑到这些消息的非 ASCII 字符集,或者是否应该将原因短语(状态描述)仅保留为低级消息和任何将使其成为“方式”的内容用户屏幕应该在响应正文中传递吗?如果我们选择本地化原因短语部分,以后有什么可以咬我们的吗?

在这种情况下,我们希望使用响应主体将新版本的资源传递给 API 客户端,并且包含其他数据并不能很好地配合它。

4

3 回答 3

4

在原因短语中传递非 ASCII 字符没有商定的方法,所以如果它需要在实验环境之外工作,我会非常小心地依赖它。

将本地化消息移动到响应正文中会更可靠。

于 2011-03-07T09:55:58.493 回答
3

正如您从 RFC 中了解的那样:

状态码供自动机使用,原因短语供人类用户使用

因此,值得尝试在简短和中肯的内容之间找到平衡,同时仍然对用户友好。我见过的许多 Web 服务都有一个状态节点(xml 或 json),其中包含代码和更人性化的消息作为响应数据的一部分。

一个潜在问题:在我们的一个 RESTful API 中,我们自定义了原因短语以帮助调试。我们正在使用 Pingdom 监控正常运行时间,它错误地仅在状态与 RFC 中建议的匹配时才接受可用的服务 - (即200 OK)。在向他们指出这是不正确的之后,我被转介到 RFC(!),尽管他们最终承认他们误解了它。

于 2011-03-07T09:38:39.173 回答
0

最佳实践似乎是为此使用 ASCII 英语消息,并假设浏览器正在做正确的事情并且根本不显示这些短语(请参阅下面的详细信息)。

HTTP/1.1 RFC 2616中定义的 HTTP 1.1 响应行的当前状态以及RFC 72307231中的更新如下:

  • 状态行的格式是HTTP-Version Status-Code Reason-Phrase CRLF
  • Reason-PhraseTEXTCR和字符之外的任何LF字符。RFC 7230 实际上说客户端应该忽略原因短语内容。浏览器不应再向用户显示这些原因短语;它们适用于基于文本的浏览器。但是,对于现代浏览器可能仍向用户显示原因短语的任何情况,我都找不到明确的文档。
  • TEXT规则仅用于不打算由消息解析器解释的描述性字段内容和值。MAY的单词仅在根据RFC 2047*TEXT的规则编码时才包含来自 ISO-8859-1(根据 RFC 2616)以外的字符集的字符。
  • RFC 2047 指定语法,例如:=?iso-8859-1?q?test_S=EEne_li=F0e?==?utf-8?b?dGVzdCBTw65uZSBsacOwZSDhmqDhm4fhmrsgz4PPgM6vz4TOuQ==?=. 这是其他 HTTP 标头的编码方式,但当前浏览器似乎不支持(在 Chrome 和 Firefox 上测试)
  • 在 Chrome 和 Firefox 上进行的简短测试表明,根据 Javascript 控制台和网络选项卡中显示的内容,使用 UTF-8 或 ISO-8859-1 作为响应短语,您的里程可能会有所不同,但 RFC 2047 mime 样式编码永远不会起作用。

这是一个非常简单的 Python 3 服务器,我用来测试它(例如,转到http://127.0.0.1:8080/UTF-8http://127.0.0.1:8080/rfc2047):

# -*- coding: utf-8 -*-
import sys
from email.header import *
from http.server import HTTPServer, BaseHTTPRequestHandler
from socketserver import ThreadingTCPServer

class TestHTTPRequestHandler(BaseHTTPRequestHandler):
    def handle(self):
        data = str(self.request.recv(1024), 'ascii')
        print("Received request: %r" % data)
        if 'GET /' in data:
            encoding = data[data.find('GET /')+4:]
            encoding = encoding[:encoding.find(' ')].lstrip('/')
            if '?' in encoding:
                encoding = encoding[:encoding.find('?')]
        else:
            encoding = "iso-8859-1"
        if encoding == 'favicon.ico':
            self.request.sendall(b'HTTP/1.1 404 Not Found\r\n')
            return
        reason_phrase = "test Sîne"
        if encoding == "rfc2047":
            encoding = "utf-8"
            reason_phrase = Header(reason_phrase, encoding).encode()
        response = (u"HTTP/1.1 500 %s\r\nContent-Length: 10\r\nContent-Type: text/plain; charset=%s\r\nConnection: Closed\r\n\r\n\"testSîn\"" % (reason_phrase, encoding))
        self.request.sendall(response.encode(encoding))

server = ThreadingTCPServer(('127.0.0.1', 8080), TestHTTPRequestHandler)
try:
    server.serve_forever()
finally:
    server.server_close()
于 2020-05-12T12:02:59.753 回答