1. 程式人生 > >重定向Http status code 303 和 302

重定向Http status code 303 和 302

Http 302

302是一個普通的重定向程式碼。直觀的看來是,請求者(瀏覽器或者模擬http請求)發起一個請求,然後服務端重定向到另一個地址。而事實上,服務端僅僅是增加一條屬性到header,location=重定向地址。而一般的,瀏覽器會自動的再去請求這個location,重新獲取資源。也就是說,這個會使得瀏覽器發起兩次請求。

Example

Client request:

GET /index.html HTTP/1.1
Host: www.example.com

Server response:

實驗

  1. 首先,我們用一個Map來儲存資訊,key為username,value為隨機數。
  2. 當我請求list的時候,跳轉到users,來獲取所有的使用者。

Map<String, Double> users = new HashMap<>();

@RequestMapping(value = "/list", method = RequestMethod.GET)
public String index(){
    return "redirect:/users";
}

@ResponseBody
@RequestMapping(value = "/users", method = RequestMethod.GET)
public ResponseEntity getUsers(){
    ResponseEntity responseEntity = new
ResponseEntity(users, HttpStatus.OK); return responseEntity; }

當時用瀏覽器訪問的時候,會明顯的看到瀏覽器地址變了,也就是說我明明請求的是list,結果你給我變成了users。然而,由於瀏覽器幫我們做了跳轉的工作,我們感覺不出來,但從位址列還是可以看到的。

檢視
通過攔截請求可以看出來,訪問了兩次:
686418-20160908223534363-1357573526.png

並且list是302,而users是200.也就是說list進行了重定向。再來看list的response:

Request URL:https://localhost:8443/list
Request Method:GET
Status Code:302 
Remote Address:127.0.0.1:8888

Response Headers
view source
Cache-Control:no-cache, no-store, max-age=0, must-revalidate
Content-Language:zh-CN
Content-Length:0
Date:Thu, 08 Sep 2016 14:31:33 GMT
Expires:0
Location:https://localhost:8443/users
Pragma:no-cache
Strict-Transport-Security:max-age=31536000 ; includeSubDomains
X-Application-Context:application:dev:8443
X-Content-Type-Options:nosniff
X-Frame-Options:DENY
X-XSS-Protection:1; mode=block

Request Headers
view source
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding:gzip, deflate, sdch, br
Accept-Language:zh-CN,zh;q=0.8
Authorization:Basic YWRtaW46dGVzdA==
Connection:keep-alive
Host:localhost:8443
Upgrade-Insecure-Requests:1
User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36

最關鍵的就是location:

Location:https://localhost:8443/users
瀏覽器獲取到這個資源定位後就GET訪問獲取。所以users的請求是這樣的:

Request URL:https://localhost:8443/users
Request Method:GET
Status Code:200 
Remote Address:127.0.0.1:8888

**Response Headers**
view source
Cache-Control:no-cache, no-store, max-age=0, must-revalidate
Content-Type:application/json;charset=UTF-8
Date:Thu, 08 Sep 2016 14:31:33 GMT
Expires:0
Pragma:no-cache
Strict-Transport-Security:max-age=31536000 ; includeSubDomains
Transfer-Encoding:chunked
X-Application-Context:application:dev:8443
X-Content-Type-Options:nosniff
X-Frame-Options:DENY
X-XSS-Protection:1; mode=block

**Request Headers**
view source
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding:gzip, deflate, sdch, br
Accept-Language:zh-CN,zh;q=0.8
Authorization:Basic YWRtaW46dGVzdA==
Connection:keep-alive
Host:localhost:8443
Upgrade-Insecure-Requests:1
User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36

redirect的另一個作用是原請求的內容將會被捨棄,即如果是post請求,redirect的時候預設是不帶引數的。與之相對應的forward的請求是轉發,只有一次請求,並且帶body轉發過去。

Http 303

303 See Other。通常是指所請求的資源在別的地方,並且同302一樣,會在header中的location標明資源的位置。在我的一個是使用過程中,我想要建立一個user,當關於這個user的key已經存在的時候,server將返回303,並且告之這個user的獲取位置。

Example
Client request:

POST / HTTP/1.1
Host: www.example.com

Server response:

實驗

我將要傳送post請求建立user,如果user已經存在則返回303


    Map<String, Double> users = new HashMap<>();

    @ResponseBody
    @RequestMapping(value = "/users", method = RequestMethod.POST)
    public ResponseEntity createUser(String username){
        Double luckNum = users.get(username);
        if (luckNum ==null){
            double random = Math.random();
            users.put(username, random);
            return new ResponseEntity(random,HttpStatus.OK);
        }else{
            MultiValueMap<String,String> headers = new HttpHeaders();
            headers.add("Location", "/users/"+username);
            return new ResponseEntity(luckNum, headers, HttpStatus.SEE_OTHER);
        }
    }

    @ResponseBody
    @RequestMapping(value = "/users/{username}", method = RequestMethod.GET)
    public ResponseEntity getUser(@PathVariable("username") String username){
        ResponseEntity responseEntity = new ResponseEntity("I'm user, My name is  "+ username+ " And my luck num is "+users.get(username), HttpStatus.OK);
        return responseEntity;
    }

傳送
686418-20160908230930207-909758310.png

檢視攔截
686418-20160908230935926-1218749076.png

可以看到,post的時候返回303,並且在返回的response的header中添加了:

Location: /users/test

所以see other的意思就是去別的地方看看。值得注意的是,如果返回303,但是沒有新增location,那麼只會檢視一條請求303.而在httpclient的預設處理中,這時候會丟擲exception:location not found。

參考