哪个HTTP重定向状态代码最适合此REST API方案?

Ase*_*ore 12 api rest redirect http bit.ly

我正在开发一个REST API.关键对象("名词")是"项目",每个项目都有唯一的ID.例如,获取ID为foo的项目的信息:

GET http://api.example.com/v1/item/foo

可以创建新项目,但客户端无法选择ID.相反,客户端发送一些表示该项目的信息.所以要创建一个新项目:

POST http://api.example.com/v1/item/
hello=world&hokey=pokey

使用该命令,服务器检查我们是否已有信息项hello=world&hokey=pokey.所以这里有两种情况.

案例1:该项目不存在; 它被创造了.这种情况很容易.

201 Created
Location: http://api.example.com/v1/item/bar

案例2:该项目已存在.这是我正在努力的地方......不确定什么是最好的重定向代码.

301 Moved Permanently302 Found303 See Other307 Temporary Redirect Location: http://api.example.com/v1/item/foo

我研究过维基百科的描述RFC 2616,但这些都不是完美的.以下是我在这种情况下寻找的具体特征:

重定向是永久性的,因为ID永远不会改变.因此,为了提高效率,客户端可以而且应该直接向ID端点发出所有未来请求.这表明301,因为其他三个是临时的.

重定向应该使用GET,即使此请求是POST.这表明303,因为所有其他技术上都应该重新使用POST方法.实际上,浏览器将使用GET for 301和302,但这是一个REST API,而不是浏览器中常规用户使用的网站.

它应该广泛使用并且易于使用.具体地,303是HTTP/1.1而301和302是HTTP/1.0.我不确定这是多少问题.

在这一点上,我倾向于303只是为了在语义上正确(使用GET,不要重新POST),只是在"临时"部分吸收它.但我不确定302是否会更好,因为在实践中它与303相同,但不需要HTTP/1.1.但如果我走下那条线,我想知道301是否因为同样的原因加上"永久"部分更好.

赞赏的想法!


编辑:让我试着用一个更具体的例子来更好地解释这个"获取或创建"操作的语义:URL缩短.无论如何,这实际上更接近我的应用程序.

对于URL缩短器,到目前为止最常见的操作是按ID检索.例如,对于http://bit.ly/4Agih5,bit.ly接收ID为4Agih5,并且必须将用户重定向到其对应的URL.

bit.ly已经有了一个API,但它不是真正的RESTful.为了举例,让我构建一个更RESTful的API.例如,查询ID可能会返回有关它的各种信息(例如分析):

GET http://api.bit.ly/item/4Agih5

现在,如果我想提交一个新的URL到bit.ly来缩短,我不知道我的URL的ID,所以我不能使用PUT.我会改用POST.

POST http://api.bit.ly/item/
url=http://stackoverflow.com/ (但编码)

如果bit.ly之前没有看过这个URL,它会为它创建一个新ID,并通过201 Created重定向到新ID.但是,如果它已经看到了该URL,它仍然会重定向我而不进行更改.这样,我可以点击该重定向位置以获取缩短的URL上的信息/元数据.

就像这个URL缩短的例子一样,在我的应用程序中,碰撞并不重要.一个URL映射到一个ID,就是这样.因此,URL之前是否缩短并不重要; 无论哪种方式,将客户端指向它的ID都是有意义的,无论是否需要首先创建ID.

所以我可能不会改变这种方法; 我只是问它最好的重定向方法.谢谢!

Jac*_*son 11

我想争论303.现在假设hello = world&hokey = pokey唯一标识项目foo,但后来项目foo的hokey值变为"smokey"?现在,这些原始值不再是该资源的唯一标识符.我认为临时重定向是合适的.

  • 我知道,我迟到了 - 无论如何,为了后人:注意REST上的重定向:人们可能需要一个代理,重定向最终会导致不可通信的跨域请求失败> http://stackoverflow.com/questions/13420417/prevent -xhr-从变向-时 - 响应 - 是-303与 - 位置的头 (2认同)

Dar*_*ler 10

我认为你正在努力解决这个问题的原因之一是因为(除非我们缺少一些关键信息)这种交互不是很合乎逻辑.

让我解释为什么我这么想.最初的前提是用户正在请求创建某些内容,并为他们希望创建的资源提供了一些关键信息.

然后,您声明如果该键信息引用现有对象,那么您希望返回该对象.问题是用户不希望检索他们希望创建新对象的现有对象.如果他们无法创建资源,因为它已经存在或存在密钥冲突,那么应该告知用户该事实.

当用户尝试创建新对象时,选择检索现有对象似乎是一种误导性的方法.

如果资源已经存在并且包含指向实体主体中现有对象的链接,则可能有一种替代方法是返回404 Bad请求.客户端应用程序可以选择吞下错误的请求错误,只需按照指向现有实体的链接,这样就可以隐藏用户的问题.这将是客户端应用程序的选择,但至少服务器的行为方式清晰.


根据新的例子,让我建议一个完全不同的方法.它可能不适合你的情况,因为魔鬼总是在细节中,但也许它会有所帮助.

从客户的角度来看,它确实对服务器是创建新的缩短的URL还是撤回现有的URL没有兴趣.实际上,服务器是否需要生成新ID是完全隐藏的实现细节.
隐藏创建过程可能非常有价值.也许服务器可以提前预测将很快请求与诸如会议之类的事件相关的许多短网址.它可以在相当长的时间内预先生成这些URL以平衡其服务器上的负载.

因此,基于这个假设,为什么不使用

GET /ShortUrl?longUrl=http://www.example.org/en/article/something-that-is-crazy-long.html&suggestion=crazyUrl
Run Code Online (Sandbox Code Playgroud)

如果网址已经存在,那么您可能会回来

303 See Other
Location: http://example.org/ShortUrl/3e4tyz
Run Code Online (Sandbox Code Playgroud)

如果以前没有,你可能会得到

303 See Other
Location: http://example.org/ShortUrl/crazyurl
Run Code Online (Sandbox Code Playgroud)

我意识到这看起来像是通过创建响应GET的东西来打破GET的规则,但我相信在这种情况下它没有任何问题,因为客户端没有要求创建缩短的URL而且实际上没有无论如何都要关心 它是幂等的,因为无论你称之为多少次都无关紧要.

我不知道答案的一个有趣问题是代理是否会缓存初始GET和重定向.这可能是一个有趣的属性,因为其他用户对同一网址的未来请求可能永远不需要实际到达原始服务器,代理可以完全处理请求.