使用URL查询参数或媒体类型参数(在Accept头中)来配置HTTP请求的响应?

21

我正在设计一个REST API,该API可以响应多种格式,其中之一是纯文本格式,可以配置以显示或隐藏响应中的某些部分(例如:章节标题或脚注)。常规的处理方式是通过URL查询参数来完成,既可以指示所需的响应类型,也可以配置选项,例如:

http://api.example.com/foo-book/ch1/?format=text&headings=false&footnotes=true

然而,一种更优雅的RESTful方式来指示所需的响应类型(而不是使用format=text URL查询参数)是使用Accept头部,例如:

Accept: text/plain; charset=utf-8

现在,除了URL之外,媒体类型可以根据RFC 2046中的规定接受参数,这些参数可以在广泛使用的text/html; charset=utf-8Accept头文件中看到,例如:audio/*; q=0.2。还可以发现特定厂商创建的MIME类型可以定义它们自己的参数,例如:

application/vnd.example-com.foo+json; version=1.0
application/vnd.example-info.bar+xml; version=2.0

那么对于像 text/html 或者 application/json 这些之前注册过的MIME类型,可以包含自定义参数来满足应用程序的需求吗?例如:

Accept: text/plain; charset=utf-8; headings=false; footnotes=true

这似乎是一个优雅的RESTful解决方案,但它也似乎违反了一些规定。 RFC 2046 §1 表示:

Parameters are modifiers of the media subtype, and as such do not
fundamentally affect the nature of the content.  The set of
meaningful parameters depends on the media type and subtype.  Most
parameters are associated with a single specific subtype.  However, a
given top-level media type may define parameters which are applicable
to any subtype of that type.  Parameters may be required by their
defining media type or subtype or they may be optional.  MIME
implementations must also ignore any parameters whose names they do
not recognize.
请提供需要翻译的具体内容。
MIME implementations must also ignore any parameters whose names they do not recognize.

这是否意味着,如果客户端识别出 text/plain 媒体类型的 footnotes=true 参数,则该客户端将不符合规范?

2个回答

15

我认为区分应该按照以下方式进行:

接受头参数与响应的打包有关。

  • 媒体类型(例如application/json
  • 字符编码(例如charset=utf-8
  • 结构(例如指定“doctype”的供应商扩展;application/vnd.example-com.foo+json; version=1.0

查询参数与所访问的资源有关。

  • 组件(例如标题和脚注)
  • 可选功能(例如格式化)
  • 约束(尤其是当处理一系列类似资源时)

如果查询参数是特定于特定响应类型的呢?例如,对于 text/plainline-length 参数:如果存在如 http://api.example.com/foo?line-length=74 的 URL,并且我使用 Accept: text/html 请求它,那么查询参数应该被忽略吗?还是响应应包含一个 Content-Location: http://api.example.com/foo 头以及相同的 URL 在 <link rel='canonical' href='http://api.example.com/foo'/>(又名 <atom:link rel='self' href='http://api.example.com/foo'/>)中,以表明在提供响应时未考虑该参数? - Weston Ruter
这可能属于Accept头,同时发送Vary: Accept(感谢@fumanchu)。 - David Eyk
5
重度依赖Accept参数让我感到紧张的一件事是:a) 客户端支持水平和b) 使用API的人的技术专业知识。有时候,RESTful设计原则以用户体验为代价而面临着架构太空飞行的危险。 - David Eyk
同意。我认为纯粹的服务器驱动协商应该与代理驱动协商相结合,以适应客户端的限制,例如通过JSON-P或通过PHP的file_get_contents()拉取数据,对于这些情况你无法提供自己的请求头。 - Weston Ruter

2

David Eyk是正确的。

如果您要更改返回的实体,应该在URI中进行。其他任何操作都会破坏缓存等各种东西。

然而,URI内部的“格式”大多是错误的。如果可以,请使用Accept。响应头已经就位,以提供平稳的体验。

但是,如果您无法使用Accept(例如在标准Web浏览器中),我建议使用DOS扩展或类似方法来覆盖Accept。

e.g.
/image (is the resource)
/image.jpg
/image.gif

谢谢,Michael。关于format参数,我意识到这将是链接到资源替代格式的唯一选择,根据HTML5的示例:<link rel=alternate href="/en/pdf" hreflang=en type=application/pdf title="English PDF">。尽管也许这种格式特定的链接并不值得称赞。 - Weston Ruter
1
理论上,你只需要将 Vary: Accept 添加到响应头中,然后就不会出现任何问题。但在实践中,HTTP 实现可能在这些细节上有问题。 - fumanchu

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