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、小尾巴~~
只要有积累,就会有进步