REST API:自定义HTTP标头 vs URL参数

133

在REST API的请求部分中,何时使用自定义HTTP头?

示例:

你会使用吗?

GET /orders/view 
(custom HTTP header) CLIENT_ID: 23

替代

GET /orders/view/client_id/23 or 
GET /orders/view/?client_id=23
9个回答

165

URL表示资源本身。 "客户端"是可以被操作的资源,因此应该是基本url的一部分:/orders/view/client/23

参数就是用来参数化访问资源的。这在发布和搜索时尤其重要:/orders/find?q=blahblah&sort=foo。参数和子资源之间有一条微妙的界限:/orders/view/client/23/active 与 /orders/view/client/23?show=active。我建议使用子资源风格,并将参数保留用于搜索。

由于每个端点都代表着一次状态转移(为了搞乱助记符),因此自定义标头只应用于不涉及资源名称(url)、资源状态(正文)或直接影响资源的参数(参数)的事物。这样留下真正的元数据请求来使用自定义标头。

HTTP有非常广泛的标头选择,涵盖了大多数你需要的东西。我见过自定义标头出现在系统对用户进行操作的请求中。代理系统将验证用户并向标头添加"X-User: userid",然后使用系统凭据击中端点。接收系统验证系统凭据是否有权代表用户进行操作,然后验证用户是否有权执行该操作。


1
谢谢您提供如此全面的答案!在移动API中,如果存在恶意代理(会剥离头部信息),您是否仍然会使用X-User? - Vasile Cotovanu
3
不,我所提到的X-User用法是在系统与系统的连接中,其中该系统代表第三方进行操作。例如,用户U与服务器A通信。服务器A使用X-User头信息向服务器B呈现凭据,表示“请使用我的凭据检查我是否有权代表用户U执行此操作。”这种情况出现在面向服务的架构中,通常使用HTTPS。移动平台几乎总是由用户本人操作,并使用适当的第一人称凭据进行交易。 - Nialscorva
9
第三段是我在 Stack Overflow 上读过的最有信息量的答案之一 ;-) - Alistair77
1
@Nialscorva 很好的解释!如果我想让用户通过授权容器(如我的移动应用程序)与我的API进行交互怎么办?现在我正在做的是,我的移动应用程序没有被授权自行执行任何操作,也没有最终用户..如果用户愿意执行操作,则必须同时提供两个凭据。 - bolbol

24

使用 HTTP Headers 发送:

  • 指令 ( 以 JSON 格式读取输入 )

  • 元数据 ( 请求发出者是谁 )

  • 每个请求都需要发送的共同数据 ( 如身份验证、会话 )

使用 Path Parameters 来进行:

  • 特定资源的请求 ( /country/state/city )

    它们必须形成逻辑层级结构

使用 Query Parameters 发送:

  • 对资源的操作请求 ( 如分页、筛选 )

1
好的指令 - Somaiah Kumbera

9

只有在没有标准或约定的情况下,我才会使用自定义头来传递信息。Darren102正在解释传递该值的典型方式。通过使用典型模式而不是使用自定义头,您的Api将更加友好。这并不是说您不会使用它们,只是它们应该是最后的选择,并且不应该已经由HTTP规范处理。


全心全意地赞同......如果有标准的方法可以完成任务,就不要重新发明轮子。 - Alessandro Santini

6

自定义标头具有以下优点:

  • 使URL免于安全问题(更安全,不在浏览器/代理缓存中)

个人而言,我只会在自己的web代码和自己的web服务器之间内部使用它们,以防需要特殊处理。


3
它们还可以被代理静默剥离/过滤。 - fusi
@fusi 很好的观点...这里有一个相关话题:https://dev59.com/WWEi5IYBdhLWcg3w7__P - Christophe Roussy

5
当你在使用REST API的请求部分时,什么时候需要使用HTTP头?
身份验证:GUID、基本身份验证、自定义令牌等。例如, 使用GUID令牌进行REST api的基本身份验证而不是用户名/密码 如果您参与在受PCI-DSS或其他安全规则覆盖的域之间传递令牌或其他类似身份验证的信息,则还必须隐藏参数,因为某些规定明确要求身份验证元素不要留在可以轻松重放的URL中(来自浏览器历史记录、代理日志等)。

1

REST 没有标准,但被广泛接受的方式是:

GET /orders/view/23

没有使用自定义标头,因此视图后面的23被假定为ID,因此您将拥有一个函数,该函数接受ID并仅生成该信息。


1

我不会使用自定义标头,因为您无法确定任何代理是否会传递它们。基于URL的方式是正确的选择。

GET /orders/view/client/23


5
我建议也不要使用自定义标头,但是损坏的代理不是原因。如果代理出现问题,应该进行修复。 - Julian Reschke

0

您可以使用自定义标头来包含有关部分处理请求的更多信息,考虑到封装不是一个好的实践。这些标头是安全的


-1

绝对没问题:

GET /orders/view/client_id/23 or 
GET /orders/view/?client_id=23

也可以:

GET /orders/view/23 or 

我认为这也应该没问题:

POST /orders/view 
(custom HTTP header) CLIENT_ID: 23

RESTful POST响应应该是HTTP 303,位置头设置为类似于“/orders/view/23”的内容。 - Rich Remer

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