目录
1、设置拦截器(ClientHttpRequestInterceptor)
一、RestTemplate方式发送HTTP请求代码示例
RestTemplate是Spring提供的用于访问Rest服务的客户端,RestTemplate提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率。
使用apache的HttpClient开发,代码复杂,还得操心资源回收等。代码很复杂,冗余代码多,稍微截个图,这是一个封装好的get请求工具:
public static String get(String url, String paramsStr) {
//创建一个默认的HttpClients对象
CloseableHttpClient createDefault = HttpClients.createDefault();
//创建一个get请求并发送参数
HttpGet httpGet = new HttpGet(url + paramsStr);
//设置http头部信息
httpGet.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1;"
+ " Win64; x64; rv:50.0) Gecko/20100101 Firefox/50.0");
httpGet.setHeader("Accept", "application/json");
httpGet.setHeader("Accept-Encoding", "gzip, deflate");
httpGet.setHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
//RequestConfig.Builder 配置器 ,我们可以通过custom获取一个新的Builder对象
RequestConfig config = RequestConfig.custom()
//设置链接超时的时间1秒钟
.setConnectTimeout(90000)
//设置读取超时1秒钟
.setSocketTimeout(90000)
//RequestConfig静态方法 setProxy 设置代理
.build();
//设置头部信息
httpGet.setConfig(config);
//实例话对象赋值
CloseableHttpResponse execute = null;
String jsonStr = "";
try {
//执行HttpClient
execute = createDefault.execute(httpGet);
//转化json格式 并防止乱码
jsonStr = EntityUtils.toString(execute.getEntity(), "UTF-8");
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
//关闭HttpClient
createDefault.close();
//关闭执行
execute.close();
//销毁GET请求
httpGet.abort();
} catch (IOException e) {
e.printStackTrace();
}
}
return jsonStr;
}
下边贴下通过RestTemplate发送Http请求的代码:
(1)发送Get请求
代码示例:
/**
* RestTemplate 发送 HTTP GET请求 --- 测试
* @throws UnsupportedEncodingException
*/
@Test
public void doHttpGetTest() throws UnsupportedEncodingException {
// -------------------------------> 获取Rest客户端实例
RestTemplate restTemplate = new RestTemplate();
// -------------------------------> 解决(响应数据可能)中文乱码 的问题
List<HttpMessageConverter<?>> converterList = restTemplate.getMessageConverters();
converterList.remove(1); // 移除原来的转换器
// 设置字符编码为utf-8
HttpMessageConverter<?> converter = new StringHttpMessageConverter(StandardCharsets.UTF_8);
converterList.add(1, converter); // 添加新的转换器(注:convert顺序错误会导致失败)
restTemplate.setMessageConverters(converterList);
// -------------------------------> (选择性设置)请求头信息
// HttpHeaders实现了MultiValueMap接口
HttpHeaders httpHeaders = new HttpHeaders();
// 给请求header中添加一些数据
httpHeaders.add("JustryDeng", "这是一个大帅哥!");
// -------------------------------> 注:GET请求 创建HttpEntity时,请求体传入null即可
// 请求体的类型任选即可;只要保证 请求体 的类型与HttpEntity类的泛型保持一致即可
String httpBody = null;
HttpEntity<String> httpEntity = new HttpEntity<String>(httpBody, httpHeaders);
// -------------------------------> URI
StringBuffer paramsURL = new StringBuffer("http://127.0.0.1:8080/http/doHttpTest");
// 字符数据最好encoding一下;这样一来,某些特殊字符才能传过去(如:flag的参数值就是“&”,不encoding的话,传不过去)
paramsURL.append("?flag=" + URLEncoder.encode("&&", "utf-8"));
URI uri = URI.create(paramsURL.toString());
// -------------------------------> 执行请求并返回结果
// 此处的泛型 对应 响应体数据 类型;即:这里指定响应体的数据装配为String
ResponseEntity<String> response =
restTemplate.exchange(uri, HttpMethod.GET, httpEntity, String.class);
// -------------------------------> 响应信息
//响应码,如:401、302、404、500、200等
System.err.println(response.getStatusCodeValue());
// 响应头
System.err.println(JSON.toJSON(response.getHeaders()));
// 响应体
if(response.hasBody()) {
System.err.println(response.getBody());
}
}
(2)发送Post请求
代码示例:
/**
* RestTemplate 发送 HTTP POST请求 --- 测试
* @throws UnsupportedEncodingException
*/
@Test
public void doHttpPostTest() throws UnsupportedEncodingException {
// -------------------------------> 获取Rest客户端实例
RestTemplate restTemplate = new RestTemplate();
// -------------------------------> (选择性设置)请求头信息
// HttpHeaders实现了MultiValueMap接口
HttpHeaders httpHeaders = new HttpHeaders();
// 设置contentType
httpHeaders.setContentType(MediaType.APPLICATION_JSON_UTF8);
// 给请求header中添加一些数据
httpHeaders.add("JustryDeng", "这是一个大帅哥!");
// ------------------------------->将请求头、请求体数据,放入HttpEntity中
// 请求体的类型任选即可;只要保证 请求体 的类型与HttpEntity类的泛型保持一致即可
// 这里手写了一个json串作为请求体 数据 (实际开发时,可使用fastjson、gson等工具将数据转化为json串)
// String httpBody = "{\"motto\":\"唉呀妈呀!脑瓜疼!\"}";
Map<String,Object> paramMap = new HashMap<>();
paramMap.put("name","是一个中文名");
paramMap.put("englishName","merry");
HttpEntity<Map<String,Object>> httpEntity = new HttpEntity<>(paramMap, httpHeaders);
// -------------------------------> URI
StringBuffer paramsURL = new StringBuffer("http://127.0.0.1:8080/http/doHttpTest");
// 字符数据最好encoding一下;这样一来,某些特殊字符才能传过去(如:flag的参数值就是“&”,不encoding的话,传不过去)
paramsURL.append("?flag=" + URLEncoder.encode("&&", "utf-8"));
URI uri = URI.create(paramsURL.toString());
// -------------------------------> 执行请求并返回结果
// 此处的泛型 对应 响应体数据 类型;即:这里指定响应体的数据装配为String
// 访问方式一:
// ResponseEntity<String> response =
// restTemplate.exchange(uri, HttpMethod.POST, httpEntity, String.class);
// 访问方式二:
ResponseEntity<String> response = restTemplate.postForEntity(uri,httpEntity,String.class);
// -------------------------------> 响应信息
//响应码,如:401、302、404、500、200等
System.err.println(response.getStatusCodeValue());
// 响应头
System.err.println(JSON.toJSON(response.getHeaders()));
// 响应体
if(response.hasBody()) {
System.err.println(response.getBody());
}
}
对应的响应端代码:
@RequestMapping("/doHttpTest")
public String doHttpGetTest(HttpServletRequest request, @RequestBody Map<String, Object> paramMap) throws IOException {
System.out.println(request.getCharacterEncoding());
// 不是请求体中的中文数据都需要转码
String JustryDeng = new String(request.getHeader("JustryDeng").getBytes("ISO-8859-1"), "utf-8");
System.out.println("获取Header传参:" + JustryDeng);
// 获取URL上的参数
String flag = request.getParameter("flag");
System.out.println("获取URL传参:" + flag);
// 接收对应的Body参数
Map<String, Object> map = paramMap;
return "访问成功!!!";
}
注:HttpServletRequest 请求中的 body 内容仅能调用 request.getInputStream(), request.getReader()和request.getParameter("key") 方法读取一次,重复读取会报 java.io.IOException: Stream closed 异常。
request.getInputStream()只能读取一次,因此如果不对HttpServletRequest进行封装,在代码中直接通过流读取body中的内容就会抛出java.io.IOException: Stream closed 异常。
HttpEntity是请求体,可放置跟请求接口对应类型的数据。在示例中添加了许多格外的操作和代码注释,所以看起来比较臃肿,使用RestTemplate简洁的代码其实是这样的:
/**
* RestTemplate 发送 HTTP POST请求 --- 测试
* @throws UnsupportedEncodingException
*/
@Test
public void doHttpPostTest() throws UnsupportedEncodingException {
// 1-------------------------------> 获取Rest客户端实例
RestTemplate restTemplate = new RestTemplate();
// 2-------------------------------> (选择性设置)请求头信息
// HttpHeaders实现了MultiValueMap接口
HttpHeaders httpHeaders = new HttpHeaders();
// 3-------------------------------> 将请求头、请求体数据,放入HttpEntity中
Map<String,Object> paramMap = new HashMap<>();
paramMap.put("name","是一个中文名");
HttpEntity<Map<String,Object>> httpEntity = new HttpEntity<>(paramMap, httpHeaders);
// 4-------------------------------> 执行请求并返回结果
ResponseEntity<String> response = restTemplate.postForEntity(
"http://127.0.0.1:8080/http/doHttpTest",httpEntity,String.class);
// 5-------------------------------> 响应信息
if(response.hasBody()) {
System.err.println(response.getBody());
}
}
当然你还可以去除注释和进行简单封装,发现它其实就几行代码,对于Get请求来说,就更加简单了,这个没什么好写的。
二、RestTemplate详解
1、RestTemplate简述
RestTemplate
是Spring的通过客户端访问RESTful服务端的核心类,和JdbcTemplate、JmsTemplate
概念相似,都是Spring提供的模板类。
RestTemplate
的行为可以通过callback回调方法和配置HttpMessageConverter
来定制,用来把对象封装到HTTP请求体,将响应信息放到一个对象中。
RestTemplate能大幅简化提交表单数据的难度,并且附带了自动转换JSON数据的功能,但只有理解了HttpEntity的组成结构(header与body),且理解了与uriVariables之间的差异,才能真正掌握其用法。这一点在Post请求更加突出。