为啥 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 是有道理的,允许浏览器显示不同的页面而不干扰。对于 PUTPATCH 请求之类的请求,情况并非如此,因为它们目前无法通过 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?的主要内容,如果未能解决你的问题,请参考以下文章

django为啥不能实现ajax

为啥我的“多对多” Django 模型中的 Django 的“add()”方法不采用?

Django 1.7 迁移不会重新创建删除的表,为啥?

Django:为啥有些模型字段会相互冲突?

为啥 Django 给我一个 404 错误

为啥这个 Django 日志记录不起作用?