开发者

Localizing reason phrase in status line of the RESTful HTTP API reponse

We have a RESTful API exposed over HTTP that in a natural way makes use of HTTP status-line (status-code and reason-phrase) to communicate the API result to the client (http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html).

For example we have the following status line for a concurrency error:

HTTP/1.1 409 Resource updated by a different user. Reload and try again.

It recently turned out those messages will be presented to the end users of the appl开发者_StackOverflow社区ication built against our API meaning we need to localize them. I'm wondering if this is an accepted approach in such scenarios, especially considering non-ASCII charset of those messages, or should the reason phrase (status description) be kept only as low level message and any content that will make its' way to the user screen should be passed in the response body? Is there anything that can bite us later on if we choose to localize the reason-phrase part?

In this case we would like to use the response body to pass the new version of the resource to the API client and including additional data doesn't see to play nicely with that.


There is no agreed-upon way to pass non-ASCII characters in the reason phrase, so I'd be very careful relying on this if it needs to work outside an experimental environment.

Moving localized messages into the response body will be more reliable.


As you'll know from the RFC:

The Status-Code is intended for use by automata and the Reason-Phrase is intended for the human user

So it's worth trying to find a balance between something short and to-the-point while still being user-friendly. Many webservices I've seen have a status node (xml or json) containing the code and a more human-friendly message as part of the response data.

One potential issue: in one of our RESTful APIs, we customised the reason phrase to aid debugging. We were monitoring uptime with Pingdom, which incorrectly only accepted a service as being available if the status matched those suggested in the RFC - (ie 200 OK). Having pointed out to them that this was incorrect, I was referred to the RFC(!), although they eventually conceded that they had misinterpreted it.


The best practice seems to be to use ASCII English messages for this, and assume that browsers are doing the right thing and not displaying these phrases at all (see the details below).

The current status of HTTP 1.1 response lines as defined in the HTTP/1.1 RFC 2616 and the update in RFC 7230 and 7231 is as follows:

  • The format of the status line is HTTP-Version Status-Code Reason-Phrase CRLF
  • The Reason-Phrase is any TEXT except for CR and LF characters. RFC 7230 actually says that A client SHOULD ignore the reason-phrase content. Browsers shouldn't be displaying these reason-phrases to the user any more; they were intended for text-based browsers. However, I can't find clear documentation on any circumstances in which modern browsers may still display the reason phrase to users.
  • The TEXT rule is only used for descriptive field contents and values that are not intended to be interpreted by the message parser. Words of *TEXT MAY contain characters from character sets other than ISO-8859-1 (according to RFC 2616) only when encoded according to the rules of RFC 2047.
  • RFC 2047 specifies syntax like: =?iso-8859-1?q?test_S=EEne_li=F0e?= or =?utf-8?b?dGVzdCBTw65uZSBsacOwZSDhmqDhm4fhmrsgz4PPgM6vz4TOuQ==?=. This is how other HTTP headers are encoded, but this doesn't seem supported by current browsers (tested on Chrome and Firefox)
  • Brief testing on Chrome and Firefox indicates that your mileage may vary using UTF-8 or ISO-8859-1 for the response phrase, based on what appears in the Javascript console and Network tabs, but the RFC 2047 mime-style encoding never works.

Here's a very simple Python 3 server that I used to test this (go to http://127.0.0.1:8080/UTF-8 or http://127.0.0.1:8080/rfc2047 for an example):

# -*- 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()
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜