起因:
今天在练习一个Django功能时,把form的method设置为POST,但是实际提交时,一直是GET方法。最后,从下面这张图发现了端倪:
第一次是method是POST方法,被重定向时,变成了GET。
继续探索,从下图中可以看出来是和多语言相关,django前面的多语言设置,会自动加上语言的路径,从而有了重定向这个操作,把POST变成了GET。
如果想要继续采用现有的方式,实现多语言,有没有办法解决这个问题呢?
概念
根据HTTP规范(RFC 7231),当客户端(如浏览器)接收到一个带有状态码为3xx(重定向)的响应时,如果要跟随这个重定向到新的URL,它应该使用GET方法发起新的请求,即使原始请求使用的是POST或其他方法。
具体来说,RFC 7231的第6.4节阐述了这一点,它说明了对于诸如301(Moved Permanently)、302(Found,虽然现在推荐使用303 See Other来明确表示应使用GET)、307(Temporary Redirect)和308(Permanent Redirect)等状态码,客户端的行为应当遵循以下原则:
- 对于301和302(以及历史遗留的使用方式),尽管早期实践中允许重定向POST请求并保持原方法,但现代实践和规范推荐在重定向时转换为GET请求,以避免潜在的副作用和不一致。
- 303 See Other明确指示客户端应该使用GET方法重定向,不论原始请求是什么方法。
- 307 Temporary Redirect和308 Permanent Redirect则保留了原始请求方法,但在实际应用中,特别是浏览器环境中,对于POST到307的重定向,虽然理论上可以保持POST方法,但实际操作中可能仍存在限制或实现差异。
因此,当一个POST请求被服务器响应以302 Found状态码时,浏览器或遵循HTTP规范的客户端会自动发起一个新的GET请求到Location头部指定的URL,而不是继续使用POST方法。这就是为什么在Django或其他Web框架中,处理POST请求后若直接返回重定向响应,原始的POST数据不会被传递到新的URL。