Custom request header of RestTemplate in SpringBoot WEB Series

Keywords: Programming JSON Mac OS X Spring

User defined request header of RestTemplate in WEB Series

The last article introduced the basic usage posture of RestTemplate, and at the end of the paper, some extended advanced usage posture were proposed. This article will focus on how to carry user-defined request header, such as setting user agent and carrying Cookie

  • Get carry request header
  • Post carries the request header
  • Interceptor mode setting uniform request header

<!-- more -->

1. Project construction

1. Configuration

Build a spring web project with SpringBoot to provide some REST services for testing

  • SpringBoot version: 2.2.1.RELEASE
  • Core dependency: spring boot state web
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

In order to make the subsequent log output more intuitive, the log output format is set in the configuration file application.yml , add

logging:
  pattern:
    console: (%msg%n%n){blue}

2. Rest Service

Add three interfaces to provide GET request, POST form and POST json object respectively, and then return the request header, request parameters, and cookie. The specific implementation logic is relatively simple and does not belong to the focus of this article, so we will not elaborate on it

@RestController
public class DemoRest {

    private String getHeaders(HttpServletRequest request) {
        Enumeration<String> headerNames = request.getHeaderNames();
        String name;

        JSONObject headers = new JSONObject();
        while (headerNames.hasMoreElements()) {
            name = headerNames.nextElement();
            headers.put(name, request.getHeader(name));
        }
        return headers.toJSONString();
    }

    private String getParams(HttpServletRequest request) {
        return JSONObject.toJSONString(request.getParameterMap());
    }

    private String getCookies(HttpServletRequest request) {
        Cookie[] cookies = request.getCookies();
        if (cookies == null || cookies.length == 0) {
            return "";
        }

        JSONObject ck = new JSONObject();
        for (Cookie cookie : cookies) {
            ck.put(cookie.getName(), cookie.getValue());
        }
        return ck.toJSONString();
    }

    private String buildResult(HttpServletRequest request) {
        return buildResult(request, null);
    }

    private String buildResult(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")
    public String get(HttpServletRequest request) {
        return buildResult(request);
    }


    @PostMapping(path = "post")
    public String post(HttpServletRequest request) {
        return buildResult(request);
    }

    @Data
    @NoArgsConstructor
    public static class ReqBody implements Serializable {
        private static final long serialVersionUID = -4536744669004135021L;
        private String name;
        private Integer age;
    }

    @PostMapping(path = "body")
    public String postBody(@RequestBody ReqBody body) {
        HttpServletRequest request =
                ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        return buildResult(request, body);
    }
}

2. Using posture

The most common requirements for carrying the request header are referer verification, anti crawling of user agent and carrying of cookie s. Using RestTemplate, the request header can be processed with the help of HttpHeaders

1. Get carries the request header

In the previous post, we introduced three methods of GET request, but getForObject/getForEntity does not meet our scenario. Here we need to introduce the exchange method

public void header() {
        RestTemplate restTemplate = new RestTemplate();

        HttpHeaders headers = new HttpHeaders();
        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;");

        // Note a few request parameters
        HttpEntity<String> res = restTemplate
                .exchange("http://127.0.0.1:8080/get?name = Gray & age = 20 ", HttpMethod.GET , new HttpEntity<>(null, headers),
                        String.class);
        log.info("get with selfDefine header: {}", res);
}

The usage posture of exchange is similar to that of postForEntity described earlier, except that there is an additional parameter to specify HttpMethod

The point is to stuff the request header into the HttpEntity

Output results

(get with selfDefine header: <200,params: {"name":["Ashes"],"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"]>

2. Post carries the request header

post carries the request header, which can also be implemented in the above way. Of course, we can directly use postForObject/postForEntity to meet the requirements

// httpHeaders are the same as above, and the relevant code is omitted here
// post with request header
MultiValueMap<String, Object> params = new LinkedMultiValueMap<>();
params.add("name", "Ashes Blog");
params.add("age", 20);

String response = restTemplate
        .postForObject("http://127.0.0.1:8080/post", new HttpEntity<>(params, headers), String.class);
log.info("post with selfDefine header: {}", response);

Output results

(post with selfDefine header: params: {"name":["Ashes 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. Interceptor mode

If we can make sure that we need to set a user-defined user agent every time we initiate a request, it will be a bit cumbersome to use the above two postures each time. Therefore, we can add a general request header by interceptor, so that when using this RestTemplate, we will carry the request header

// With the help of interceptor, the uniform request header is realized
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 = Gray & age = 20 ", String.class );
log.info("get with selfDefine header by Interceptor: {}", response);

The above posture is more suitable for general scenarios, test output

(get with selfDefine header by Interceptor: params: {"name":["Ashes"],"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. Ask the head to use the wrong posture

When we use custom request header, we need to pay special attention to it. Improper use of HttpHeaders may lead to request header explosion

/**
 * Wrong request head use posture
 */
public void errorHeader() {
    RestTemplate restTemplate = new RestTemplate();

    int i = 0;
    // In order to reuse headers and avoid creating this object every time, but adding the request header by adding in the loop, the request header will expand more and more, and eventually lead to the request overrun
    // In this case, either change add to set or do not do so in the loop
    HttpHeaders headers = new HttpHeaders();
    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 = Gray & age = 20 ", HttpMethod.GET ,
                new HttpEntity<>(null, headers), String.class);
        log.info("get with selfDefine header: {}", res);
    }
}

The key points of the above demonstration are

  • Want to reuse HttpHeaders
  • headers.add Method to add the request header; not the previous set mode

The output is as follows. Please note that after each request, the request header expands once

(get with selfDefine header: <200,params: {"name":["Ashes"],"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 with selfDefine header: <200,params: {"name":["Ashes"],"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 with selfDefine header: <200,params: {"name":["Ashes"],"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 with selfDefine header: <200,params: {"name":["Ashes"],"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"]>

2. Others

0. Project & series

Series of blog posts

Source code

1. A gray Blog

It's not as good as a letter. The above contents are all from one family. Due to limited personal ability, there are inevitably omissions and mistakes. If you find a bug or have better suggestions, you are welcome to criticize and correct, and thank you

The following is a gray personal blog, recording all the blog articles in study and work. Welcome to visit

Posted by mysterbx on Mon, 29 Jun 2020 18:51:26 -0700