RestTemplate中post請求實用分析
1、最近在做相關平台對接工作。對接第一步需要在後端完成認證,拿到對方平台的access_token。由于對方文檔不是很詳細,根據認證需要的參數進行了多種嘗試。順帶學習一下RestTemplate發post的請求的各種姿勢。記錄在此,以便檢視。
2、往後端發post請求一般分為兩種,
一種是普通的表單送出(Content-Type: application/x-www-form-urlencoded)。
另一種是JSON送出(Content-Type: application/json)。
當然背景接收的方式也不同,
普通表單送出從request.getParameter()就能擷取。
JSON送出的的資料在io流中,可以通過request.getInputStream()擷取。spring為我們提供了@RequestBody注解,簡單易用。
3、了解上述内容之後,下面進行試驗
①模拟表單送出(要知道,post請求也可以使用url傳參奧)
/**
* 1、使用uri傳參形式,把參數拼接到url後面,并在占位符裡給每個參數指派一定意義的名字。然後把參數封裝到
* Map中。 占位符中的參數名會去對應Map中的key找到參數的值以完成替換。
* 傳參并攜帶請求頭
*/
@GetMapping("/auth1")
public void auth1() {
try {
Map uriVariables = new LinkedHashMap(4);
uriVariables.put("username", "name");
uriVariables.put("password", "1234");
uriVariables.put("type", "client");
uriVariables.put("grant_type", "password");
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic aW90OmlvdA==");
HttpEntity httpEntity = new HttpEntity(null, headers);
ResponseEntity<String> entity = restTemplate.postForEntity("http://192.168.1.111:8086/auth/server?username={username}&password={password}&type={type}&grant_type={grant_type}", httpEntity, String.class, uriVariables);
if (entity.getStatusCode().is2xxSuccessful()) {
System.out.println(entity.getBody());
} else {
log.error("認證失敗:[{}]", entity);
}
} catch (Exception e) {
log.error("認證異常:[{}]", e.getMessage());
}
}
/**
* 2、使用uri傳參形式,把參數拼接到url後面,在占位符裡寫上參數的索引位置。然後把參數放在可變長變量中。
* 實際參數會根據參數索引位置完成替換
* 傳參并攜帶請求頭
*/
@GetMapping("/auth2")
public void auth2() {
try {
final String username = "name";
final String password = "1234";
final String type = "client";
final String grant_type = "password";
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic aW90OmlvdA==");
HttpEntity httpEntity = new HttpEntity(null, headers);
ResponseEntity<String> entity = restTemplate.postForEntity("http://192.168.1.111:8086/auth/server?username={0}&password={1}&type={2}&grant_type={3}", httpEntity, String.class, username, password, type, grant_type);
if (entity.getStatusCode().is2xxSuccessful()) {
System.out.println(entity.getBody());
} else {
log.error("認證失敗:[{}]", entity);
}
} catch (Exception e) {
log.error("認證異常:[{}]", e.getMessage());
}
}
/**
* 3、把參數封裝到LinkedMultiValueMap中,使用HttpEntity一并封裝表單資料和請求頭
* 傳參并攜帶請求頭
*/
@GetMapping("/auth3")
public void auth3() {
try {
MultiValueMap body = new LinkedMultiValueMap(4);
body.add("username", "name");
body.add("password", "1234");
body.add("type", "client");
body.add("grant_type", "password");
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic aW90OmlvdA==");
HttpEntity httpEntity = new HttpEntity(body, headers);
ResponseEntity<String> entity = restTemplate.postForEntity("http://192.168.1.111:8086/auth/server", httpEntity, String.class);
if (entity.getStatusCode().is2xxSuccessful()) {
System.out.println(entity.getBody());
} else {
log.error("認證失敗:[{}]", entity);
}
} catch (Exception e) {
log.error("認證異常:[{}]", e.getMessage());
}
}
/**
* 4、把參數封裝到LinkedMultiValueMap中,隻發送表單資料可以不使用HttpEntity
* 傳參不攜帶請求頭
*/
@GetMapping("/auth4")
public void auth4() {
try {
MultiValueMap body = new LinkedMultiValueMap(4);
body.add("username", "name");
body.add("password", "1234");
body.add("type", "client");
body.add("grant_type", "password");
ResponseEntity<String> entity = restTemplate.postForEntity("http://192.168.1.111:8086/auth/server", body, String.class);
if (entity.getStatusCode().is2xxSuccessful()) {
System.out.println(entity.getBody());
} else {
log.error("認證失敗:[{}]", entity);
}
} catch (Exception e) {
log.error("認證異常:[{}]", e.getMessage());
}
}
②JSON送出的形式
/**
* 5、資料可以用map封裝、可以用實體類封裝、也可以是json格式的字元串
* 攜帶請求頭
*/
@GetMapping("/auth5")
public void auth5() {
try {
Map body = new LinkedHashMap(4);
body.put("username", "name");
body.put("password", "1234");
body.put("type", "client");
body.put("grant_type", "password");
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic aW90OmlvdA==");
HttpEntity httpEntity = new HttpEntity(body, headers);
ResponseEntity<String> entity = restTemplate.postForEntity("http://192.168.1.111:8086/auth/server2", httpEntity, String.class);
if (entity.getStatusCode().is2xxSuccessful()) {
System.out.println(entity.getBody());
} else {
log.error("認證失敗:[{}]", entity);
}
} catch (Exception e) {
log.error("認證異常:[{}]", e.getMessage());
}
}
/**
* 5、資料可以用map封裝、可以用實體類封裝、也可以是json格式的字元串
* 不攜帶請求頭
*/
@GetMapping("/auth6")
public void auth6() {
try {
Map body = new LinkedHashMap(4);
body.put("username", "name");
body.put("password", "1234");
body.put("type", "client");
body.put("grant_type", "password");
ResponseEntity<String> entity = restTemplate.postForEntity("http://192.168.1.111:8086/auth/server2", body, String.class);
if (entity.getStatusCode().is2xxSuccessful()) {
System.out.println(entity.getBody());
} else {
log.error("認證失敗:[{}]", entity);
}
} catch (Exception e) {
log.error("認證異常:[{}]", e.getMessage());
}
}
4、附上背景接收代碼
@PostMapping("/server")
public String server(String username, String password, String type, String grant_type, HttpServletRequest request) {
System.out.println(username);
System.out.println(password);
System.out.println(type);
System.out.println(grant_type);
String header = request.getHeader("Authorization");
System.out.println(header);
return "ok";
}
@PostMapping("/server2")
public String server(@RequestBody Object obj, HttpServletRequest request) {
System.out.println(obj);
String header = request.getHeader("Authorization");
System.out.println(header);
return "ok";
}
5、最後附上抓包資料,可以清楚的觀察到資料的傳送格式以及Content-Type的形式
POST /auth/server?username=name&password=1234&type=client&grant_type=password HTTP/1.1
Accept: text/plain, application/json, application/*+json, */*
Authorization: Basic aW90OmlvdA==
Content-Length: 0
Host: 192.168.1.111:8086
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.5.8 (Java/1.8.0_131)
Accept-Encoding: gzip,deflate
POST /auth/server?username=name&password=1234&type=client&grant_type=password HTTP/1.1
Accept: text/plain, application/json, application/*+json, */*
Authorization: Basic aW90OmlvdA==
Content-Length: 0
Host: 192.168.1.111:8086
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.5.8 (Java/1.8.0_131)
Accept-Encoding: gzip,deflate
POST /auth/server HTTP/1.1
Accept: text/plain, application/json, application/*+json, */*
Authorization: Basic aW90OmlvdA==
Content-Type: application/x-www-form-urlencoded;charset=UTF-8
Content-Length: 59
Host: 192.168.1.111:8086
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.5.8 (Java/1.8.0_131)
Accept-Encoding: gzip,deflate
username=name&password=1234&type=client&grant_type=password
POST /auth/server HTTP/1.1
Accept: text/plain, application/json, application/*+json, */*
Content-Type: application/x-www-form-urlencoded;charset=UTF-8
Content-Length: 59
Host: 192.168.1.111:8086
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.5.8 (Java/1.8.0_131)
Accept-Encoding: gzip,deflate
username=name&password=1234&type=client&grant_type=password
POST /auth/server2 HTTP/1.1
Accept: text/plain, application/json, application/*+json, */*
Authorization: Basic aW90OmlvdA==
Content-Type: application/json;charset=UTF-8
Content-Length: 77
Host: 192.168.1.111:8086
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.5.8 (Java/1.8.0_131)
Accept-Encoding: gzip,deflate
{"username":"name","password":"1234","type":"client","grant_type":"password"}
POST /auth/server2 HTTP/1.1
Accept: text/plain, application/json, application/*+json, */*
Content-Type: application/json;charset=UTF-8
Content-Length: 77
Host: 192.168.1.111:8086
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.5.8 (Java/1.8.0_131)
Accept-Encoding: gzip,deflate
{"username":"name","password":"1234","type":"client","grant_type":"password"}
6、總結:
在做平台對接的時候,一開始使用的是第三種形式發送post請求。經過一番調試,沒有認證成功。但是我通過postman請求是成功的。通過抓包,發現postman發送資料的形式是前面兩種形式,即把參數放在url上。後來在程式中切換到前兩種形式,成功認證并擷取到對方平台的accessToken。由于不知道對方代碼的實作方式,故無法進一步分析。
在我的試驗中以前三種形式進行表單送出都能正常擷取到資料,若今後遇到類似問題,要做到舉一反三、觸類旁通。
7、小尾巴~~
隻要有積累,就會有進步