为啥 Django 的 HTTPResponseRedirect 使用相同的 HTTP 方法进行 PUT 而不是 POST?
Posted
技术标签:
【中文标题】为啥 Django 的 HTTPResponseRedirect 使用相同的 HTTP 方法进行 PUT 而不是 POST?【英文标题】:Why does Django's HTTPResponseRedirect use the same HTTP method for PUT but not POST?为什么 Django 的 HTTPResponseRedirect 使用相同的 HTTP 方法进行 PUT 而不是 POST? 【发布时间】:2015-02-13 04:48:37 【问题描述】:我有一个 Django 项目,我在其中使用视图来处理不同的 HTTP 方法。 POST
处理对象的创建,然后重定向到与 GET
相同的视图(或者我认为),使用 Django 的 redirect()
快捷方式(HTTPResponseRedirect
)返回新创建的对象。这工作得很好。我用PUT
尝试了同样的事情,但我陷入了重定向循环。在摸索了一会儿后,我偶然发现了this SO answer,然后我推断由于重定向不处理POST
数据,因此请求变成了GET
。
当我从POST
进行重定向时,我通过查看日志确认了这一点:
[15/Dec/2014 00:47:43] "POST /client/151/ HTTP/1.1" 302 0
[15/Dec/2014 00:47:43] "GET /client/151/ HTTP/1.1" 200 395
但是,PUT
仍然是 PUT
,并让我进入重定向循环,直到它出错。
[14/Dec/2014 23:07:36] "PUT /api/asset/6779 HTTP/1.1" 301 0
[14/Dec/2014 23:07:37] "PUT /api/asset/6779/ HTTP/1.1" 302 0
[14/Dec/2014 23:07:37] "PUT /api/asset/6779 HTTP/1.1" 301 0
[14/Dec/2014 23:07:38] "PUT /api/asset/6779/ HTTP/1.1" 302 0
[14/Dec/2014 23:07:38] "PUT /api/asset/6779 HTTP/1.1" 301 0
[14/Dec/2014 23:07:39] "PUT /api/asset/6779/ HTTP/1.1" 302 0
[14/Dec/2014 23:07:39] "PUT /api/asset/6779 HTTP/1.1" 301 0
[14/Dec/2014 23:07:40] "PUT /api/asset/6779/ HTTP/1.1" 302 0
[14/Dec/2014 23:07:40] "PUT /api/asset/6779 HTTP/1.1" 301 0
[14/Dec/2014 23:07:41] "PUT /api/asset/6779/ HTTP/1.1" 302 0
[14/Dec/2014 23:07:41] "PUT /api/asset/6779 HTTP/1.1" 301 0
[14/Dec/2014 23:07:42] "PUT /api/asset/6779/ HTTP/1.1" 302 0
重定向不应该使用GET
吗?我明白发生了什么,但不知道为什么?什么给了?
编辑
# urls.py
url(r'^$', views.put_vs_post_redirect),
# views.py
from django.shortcuts import redirect
def put_vs_post_redirect(request, asset_id):
if request.method == 'GET':
return HTTPResponse('Get request')
elif request.method == 'POST':
return redirect('/')
elif request.method == 'PUT':
return redirect('/')
【问题讨论】:
相关:***.com/questions/13628831/… 如何让用户代理执行 PUT?从 POST 重定向到 GET 是有意义的,因为您可以让浏览器使用 POST(表单)而不是 PUT 浏览到页面。看来您正在编写 API。为什么不直接在 200 OK 响应中将 URI 返回到创建的对象(或者只是记录它是您放置它的位置)并让用户代理对此采取行动?此外,您 POST 带有斜杠,而 PUT 没有。这是故意的吗? @Anton 很重要。谢谢。您的解决方法是可以接受的,但我试图完成的是,当 PUT 完成后,我返回新对象,因此我重定向到旨在给我一个对象的 GET。在这一点上,我有一个解决方法,但我更感兴趣的是弄清楚这是 Django 做的还是在 HTTP 级别做的。 这是在 HTTP 级别完成的,特别是在客户端实现中。 【参考方案1】:正如 cmets 中所述,这完全取决于客户端,并非所有客户端都以相同的方式处理重定向。您可以在 Stack Overflow 上找到 a decent explanation of the redirect codes 和 why a 301 should drop POST data。
当使用301
(通常是302
)重定向时,大多数浏览器会丢弃POST
数据并发出GET
请求。这主要是因为浏览器一直这样做,而POST
请求最常来自网络表单,因此重定向结果为GET
是有道理的,允许浏览器显示不同的页面而不干扰。对于 PUT
或 PATCH
请求之类的请求,情况并非如此,因为它们目前无法通过 Web 表单发送,并且通常按照不同的规则进行播放。
如果您希望在302
重定向上维护POST
数据,您应该考虑using a 307
redirect instead。 307
请求应维护请求方法以及请求正文作为结果。
如果您希望在301
重定向中维护POST
数据,目前有a draft for a 308
status code 可以像307
一样工作,但是是永久性的。
您可以强制重定向使用带有a 303
redirect 的GET
请求。它的工作方式与302
非常相似,但它强制要求请求方法始终是GET
请求。它经常用于异步任务的 API。
【讨论】:
很好的答案。感谢您的解释和建议的解决方案。以上是关于为啥 Django 的 HTTPResponseRedirect 使用相同的 HTTP 方法进行 PUT 而不是 POST?的主要内容,如果未能解决你的问题,请参考以下文章