1.概述
转载:RestTemplate之自定义请求头
本篇将主要集中在如何携带自定义的请求头,如设置User-Agent,携带Cookie
Get携带请求头
Post携带请求头
拦截器方式设置统一请求头
2. 项目搭建
2.1. 配置
借助SpringBoot搭建一个SpringWEB项目,提供一些用于测试的REST服务
SpringBoot版本:2.2.1.RELEASE
核心依赖: spring-boot-stater-web
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency></dependencies>
为了后续输出的日志更直观,这里设置了一下日志输出格式,在配置文件application.yml中,添加
logging:
pattern:
console:(%msg%n%n){blue}
3.Rest服务
添加三个接口,分别提供GET请求,POST表单,POST json对象,然后返回请求头、请求参数、cookie,具体实现逻辑相对简单,也不属于本篇重点,因此不赘述说明
@RestControllerpublicclassDemoRest{privateStringgetHeaders(HttpServletRequest request){Enumeration<String> headerNames = request.getHeaderNames();String name;JSONObject headers =newJSONObject();while(headerNames.hasMoreElements()){
name = headerNames.nextElement();
headers.put(name, request.getHeader(name));}return headers.toJSONString();}privateStringgetParams(HttpServletRequest request){returnJSONObject.toJSONString(request.getParameterMap());}privateStringgetCookies(HttpServletRequest request){Cookie[] cookies = request.getCookies();if(cookies ==null|| cookies.length ==0){return"";}JSONObject ck =newJSONObject();for(Cookie cookie : cookies){
ck.put(cookie.getName(), cookie.getValue());}return ck.toJSONString();}privateStringbuildResult(HttpServletRequest request){returnbuildResult(request,null);}privateStringbuildResult(HttpServletRequest request,Object obj){String params =getParams(request);String headers =getHeaders(request);String cookies =getCookies(request);if(obj !=null){
params +=" | "+ obj;}return"params: "+ params +"\nheaders: "+ headers +"\ncookies: "+ cookies;}@GetMapping(path ="get")publicStringget(HttpServletRequest request){returnbuildResult(request);}@PostMapping(path ="post")publicStringpost(HttpServletRequest request){returnbuildResult(request);}@Data@NoArgsConstructorpublicstaticclassReqBodyimplementsSerializable{privatestaticfinallong serialVersionUID =-4536744669004135021L;privateString name;privateInteger age;}@PostMapping(path ="body")publicStringpostBody(@RequestBodyReqBody body){HttpServletRequest request =((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();returnbuildResult(request, body);}}
4.使用姿势
最常见的携带请求头的需求,无非是referer校验,user-agent的防爬以及携带cookie,使用RestTemplate可以借助HttpHeaders来处理请求头
4.1. Get携带请求头
前一篇博文介绍了GET请求的三种方式,但是getForObject/getForEntity都不满足我们的场景,这里需要引入exchange方法
publicvoidheader(){RestTemplate restTemplate =newRestTemplate();HttpHeaders headers =newHttpHeaders();
headers.set("user-agent","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36");
headers.set("cookie","my_user_id=haha123; UN=1231923;gr_user_id=welcome_yhh;");// 注意几个请求参数HttpEntity<String> res = restTemplate
.exchange("http://127.0.0.1:8080/get?name=一灰灰&age=20",HttpMethod.GET,newHttpEntity<>(null, headers),String.class);
log.info("get with selfDefine header: {}", res);}
exchange的使用姿势和我们前面介绍的postForEntity差不多,只是多了一个指定HttpMethod的参数而已
重点在于将请求头塞入HttpEntity
输出结果
(get withselfDefine header:<200,params:{"name":["一灰灰"],"age":["20"]}
headers:{"cookie":"my_user_id=haha123; UN=1231923;gr_user_id=welcome_yhh;","host":"127.0.0.1:8080","connection":"keep-alive","accept":"text/plain, application/json, application/*+json, */*","user-agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36"}
cookies:{"my_user_id":"haha123","UN":"1231923","gr_user_id":"welcome_yhh"},[Content-Type:"text/plain;charset=UTF-8",Content-Length:"447",Date:"Mon, 29 Jun 2020 07:48:49 GMT"]>
3.2. Post携带请求头
post携带请求头,也可以利用上面的方式实现;当然我们一般直接借助postForObject/postForEntity就可以满足需求了
// httpHeaders 和上面的一致,这里省略相关代码// post 带请求头MultiValueMap<String,Object> params =newLinkedMultiValueMap<>();
params.add("name","一灰灰Blog");
params.add("age",20);String response = restTemplate
.postForObject("http://127.0.0.1:8080/post",newHttpEntity<>(params, headers),String.class);
log.info("post with selfDefine header: {}", response);
输出结果
(post withselfDefine header: params:{"name":["一灰灰Blog"],"age":["20"]}
headers:{"content-length":"338","cookie":"my_user_id=haha123; UN=1231923;gr_user_id=welcome_yhh;","host":"127.0.0.1:8080","content-type":"multipart/form-data;charset=UTF-8;boundary=2VJHo9r6lYgR_WoSBy1FQC40jvBvGtLk7QUaymGg","connection":"keep-alive","accept":"text/plain, application/json, application/*+json, */*","user-agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36"}
cookies:{"my_user_id":"haha123","UN":"1231923","gr_user_id":"welcome_yhh"}
3.3. 拦截器方式
如果我们可以确定每次发起请求时,都要设置一个自定义的 User-Agent,每次都使用上面的两种姿势就有点繁琐了,因此我们是可以通过拦截器的方式来添加通用的请求头,这样使用这个RestTemplate时,都会携带上请求头
// 借助拦截器的方式来实现塞统一的请求头ClientHttpRequestInterceptor interceptor =(httpRequest, bytes, execution)->{
httpRequest.getHeaders().set("user-agent","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36");
httpRequest.getHeaders().set("cookie","my_user_id=haha123; UN=1231923;gr_user_id=interceptor;");return execution.execute(httpRequest, bytes);};
restTemplate.getInterceptors().add(interceptor);
response = restTemplate.getForObject("http://127.0.0.1:8080/get?name=一灰灰&age=20",String.class);
log.info("get with selfDefine header by Interceptor: {}", response);
上面这个使用姿势比较适用于通用的场景,测试输出
(get withselfDefine header by Interceptor: params:{"name":["一灰灰"],"age":["20"]}
headers:{"cookie":"my_user_id=haha123; UN=1231923;gr_user_id=interceptor;","host":"127.0.0.1:8080","connection":"keep-alive","accept":"text/plain, application/json, application/*+json, */*","user-agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36"}
cookies:{"my_user_id":"haha123","UN":"1231923","gr_user_id":"interceptor"}
4.4. 请求头错误使用姿势
在我们使用自定义请求头时,有一个需要特殊重视的地方,HttpHeaders使用不当,可能导致请求头爆炸
/**
* 错误的请求头使用姿势
*/publicvoiderrorHeader(){RestTemplate restTemplate =newRestTemplate();int i =0;// 为了复用headers,避免每次都创建这个对象,但是在循环中又是通过 add 方式添加请求头,那么请求头会越来越膨胀,最终导致请求超限// 这种case,要么将add改为set;要么不要在循环中这么干HttpHeaders headers =newHttpHeaders();while(++i <5){
headers.add("user-agent","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36");
headers.add("cookie","my_user_id=haha123; UN=1231923;gr_user_id=welcome_yhh;");HttpEntity<String> res = restTemplate.exchange("http://127.0.0.1:8080/get?name=一灰灰&age=20",HttpMethod.GET,newHttpEntity<>(null, headers),String.class);
log.info("get with selfDefine header: {}", res);}}
上面演示的关键点为
希望复用 HttpHeaders
headers.add 方式添加请求头;而不是前面的 set方式
输出如下,请注意每一次请求过后,请求头膨胀了一次
(get withselfDefine header:<200,params:{"name":["一灰灰"],"age":["20"]}
headers:{"cookie":"my_user_id=haha123; UN=1231923;gr_user_id=welcome_yhh;","host":"127.0.0.1:8080","connection":"keep-alive","accept":"text/plain, application/json, application/*+json, */*","user-agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36"}
cookies:{"my_user_id":"haha123","UN":"1231923","gr_user_id":"welcome_yhh"},[Content-Type:"text/plain;charset=UTF-8",Content-Length:"447",Date:"Mon, 29 Jun 2020 07:48:49 GMT"]>(get withselfDefine header:<200,params:{"name":["一灰灰"],"age":["20"]}
headers:{"cookie":"my_user_id=haha123; UN=1231923;gr_user_id=welcome_yhh;; my_user_id=haha123; UN=1231923;gr_user_id=welcome_yhh;","host":"127.0.0.1:8080","connection":"keep-alive","accept":"text/plain, application/json, application/*+json, */*","user-agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36"}
cookies:{"my_user_id":"haha123","UN":"1231923","gr_user_id":"welcome_yhh"},[Content-Type:"text/plain;charset=UTF-8",Content-Length:"503",Date:"Mon, 29 Jun 2020 07:48:49 GMT"]>(get withselfDefine header:<200,params:{"name":["一灰灰"],"age":["20"]}
headers:{"cookie":"my_user_id=haha123; UN=1231923;gr_user_id=welcome_yhh;; my_user_id=haha123; UN=1231923;gr_user_id=welcome_yhh;; my_user_id=haha123; UN=1231923;gr_user_id=welcome_yhh;","host":"127.0.0.1:8080","connection":"keep-alive","accept":"text/plain, application/json, application/*+json, */*","user-agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36"}
cookies:{"my_user_id":"haha123","UN":"1231923","gr_user_id":"welcome_yhh"},[Content-Type:"text/plain;charset=UTF-8",Content-Length:"559",Date:"Mon, 29 Jun 2020 07:48:49 GMT"]>(get withselfDefine header:<200,params:{"name":["一灰灰"],"age":["20"]}
headers:{"cookie":"my_user_id=haha123; UN=1231923;gr_user_id=welcome_yhh;; my_user_id=haha123; UN=1231923;gr_user_id=welcome_yhh;; my_user_id=haha123; UN=1231923;gr_user_id=welcome_yhh;; my_user_id=haha123; UN=1231923;gr_user_id=welcome_yhh;","host":"127.0.0.1:8080","connection":"keep-alive","accept":"text/plain, application/json, application/*+json, */*","user-agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36"}
cookies:{"my_user_id":"haha123","UN":"1231923","gr_user_id":"welcome_yhh"},[Content-Type:"text/plain;charset=UTF-8",Content-Length:"615",Date:"Mon, 29 Jun 2020 07:48:49 GMT"]>
版权归原作者 九师兄 所有, 如有侵权,请联系我们删除。