简介

主要记录了使用 spring 重定向时遇到的问题,以及重新熟悉 HTTP 3xx 中重定向状态码的意义。

前言

最近接手的一个项目需要在 POST 接口中处理逻辑,完成后让浏览器重定向到首页,请求方式需要变成 GET
结果一直提示 405 方法不支持。折腾了个把都没找到问题原因,没想到是重定向的状态码有问题。

问题

一般情况下,在 Spring下重定向到页面时会使用 ModelAndView,也就是这样:

    @PostMapping("handle")
    public String handle(){
        // do something ...
        return "redirect:/";
    }

这种类似的情况下返回的是:

POST http://localhost:8080/tdh-portal/cas

HTTP/1.1 302 Found
Content-Language: zh-CN
Location: http://localhost:8080/
Content-Length: 0
Server: Jetty(9.4.z-SNAPSHOT)

<Response body is empty>

Response code: 302 (Found); Time: 119ms; Content length: 0 bytes

也不知道从哪里复制了一段代码 😂 ,主要部分如下:

    @PostMapping("handle")
    public ResponseEntity<?> handle(){
        // do something ...
        return ResponseEntity
            .status(HttpStatus.TEMPORARY_REDIRECT)
            .header(HttpHeaders.LOCATION, "/")
            .build();
    }

响应信息则是这样

POST http://localhost:8080/handle

HTTP/1.1 307 Temporary Redirect
Set-Cookie: JSESSIONID=node0123krmz4upibb18jz7ov4us1pw1.node0;Path=/
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Location: /
Content-Length: 0
Server: Jetty(9.4.z-SNAPSHOT)

<Response body is empty>

Response code: 307 (Temporary Redirect); Time: 4916ms; Content length: 0 bytes

可以看到两种方式主要响应码不同 302307。经过查阅相关文档发现意义大不相同:

编码含义处理方法
302FoundGET 方法不会发生变更,其他方法有可能会变更为 GET 方法。1
307Temporary Redirect方法和消息主体都不发生变化。

典型应用场景:

302:由于不可预见的原因该页面暂不可用。在这种情况下,搜索引擎不会更新它们的链接。
307:由于不可预见的原因该页面暂不可用。在这种情况下,搜索引擎不会更新它们的链接。当站点支持非 GET 方法的链接或操作的时候,该状态码优于 302 状态码。

302307 最主要的不同点在于方法和消息体是否发生变化。所以导致用POST方法请求接口时无法重定向到使用GET方法的页面。
经过查看重定向相关的响应码规范,修改代码:

    @PostMapping("handle")
    public ResponseEntity<?> handle(){
        // do something ...
        return ResponseEntity
            .status(HttpStatus.SEE_OTHER)
            .header(HttpHeaders.LOCATION, "/")
            .build();
    }

这里使用 303 主要是为了验证成功跳转防止重复触发。

HTTP 的重定向

不同类型的重定向映射可以划分为三个类别:

  1. 永久重定向
  2. 临时重定向
  3. 特殊重定向

永久重定向意味着原来的URL不应再被使用,而应优选用新的URL,这种关系是永久性的,通常应用于网站重构,301,308
临时重定向顾名思义这种关系是临时性的,有时候请求的资源无法从其标准地址访问,但是却可以从另外的地方访问,302,303,307
特殊重定向是指 300304,不同于其他方式直接给定url跳转重定向,没有特定的处理方式,也可能返回多个能重定向的url供手动选择。

常见重定向响应码:

编码含义说明
300Multiple Choice不常用:所有的选项在消息主体的 HTML 页面中列出。
301Moved PermanentlyGET 方法不会发生变更,其他方法有可能会变更为 GET 方法。2
302FoundGET 方法不会发生变更,其他方法有可能会变更为 GET 方法。3
303See OtherGET 方法不会发生变更,其他方法会变更为 GET 方法(消息主体会丢失)。
304Not Modified发送用于重新验证的条件请求。表示缓存的响应仍然是新鲜的并且可以使用。
307Temporary Redirect方法和消息主体都不发生变化。
308Permanent Redirect方法和消息主体都不发生变化。

延伸

  1. HTTP 的重定向

  1. 该规范无意使方法发生改变,但在实际应用中用户代理会这么做。 307 状态码被创建用来消除在使用非 GET 方法时的歧义行为。 ↩︎

  2. 该规范无意使方法发生改变,但在实际应用中用户代理会这么做。 308 状态码被创建用来消除在使用非 GET 方法时的歧义行为。 ↩︎

  3. 该规范无意使方法发生改变,但在实际应用中用户代理会这么做。 307 状态码被创建用来消除在使用非 GET 方法时的歧义行为。 ↩︎