重定向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:
實驗
- 首先,我們用一個Map來儲存資訊,key為username,value為隨機數。
- 當我請求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。然而,由於瀏覽器幫我們做了跳轉的工作,我們感覺不出來,但從位址列還是可以看到的。
檢視
通過攔截請求可以看出來,訪問了兩次:
並且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;
}
傳送
檢視攔截
可以看到,post的時候返回303,並且在返回的response的header中添加了:
Location: /users/test
所以see other的意思就是去別的地方看看。值得注意的是,如果返回303,但是沒有新增location,那麼只會檢視一條請求303.而在httpclient的預設處理中,這時候會丟擲exception:location not found。