Problem of converting pit'+'to space in http request parameter

Problem of converting pit'+'to space in http request parameter

I encountered a problem in my work where the parameter carrying the'+'number was converted to a space when we requested the interface of another service through the RestTemplate method provided by SpringBoot

1. Prerequisites

  • The first thing we need to know is that the parameters carried in the HTTP request with a'+'request backend are replaced with spaces when tomcat passes.

We arrived through debug

  • processParameters method in public final class Parameters class

After layers of dolls he will enter the following methods

  • convert method in public final class UDecoder {} class

Here's a closer look https://www.cnblogs.com/thisiswhy/p/12119126.html

As we know above, "+" becomes a space after tomcat processing

2. Understanding transcoding, decoding

	String encode = URLEncoder.encode("come +here=", "UTF-8");
        System.out.println(encode);
        String decode = URLDecoder.decode(encode, "UTF-8");
        System.out.println(decode);
        String decodeDemo = URLDecoder.decode("come +here=/yuftujy", "UTF-8");
        System.out.println(decodeDemo);
/*
*	output
*	come+%2Bhere%3D
*	come +here=
*	come  here=/yuftujy
*/
tomcattranscodingDecode
" "" ""+"" "
"+"" ""%2B""+"
"=""=""%3D""="

We found a problem with spaces. Instead of becoming the'%20'we expected after transcoding, he became a'+', and the'+' number would become a space again after tomcat?

What problems does this cause, and how does the backend handle spaces?

This is a huge pit!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

3. Discover problems

Now let's combine the issues at work, and on the client side, request additional service parameters with "+" using RestTemplate provided by SpringBoot.

  • Knowing that admId has gone through tomcat two times from the beginning to the end of the request

I found three cases in debugging

1. Normal requests: http://localhost:8080/cdata?admId=S9Y +qEERxGVFo0DE8mruGVmVYNJraVwZyijimEv6w=

@GetMapping("/cdata")
public Object cdata(@RequestParam String admId) throws Exception{
    
    System.out.println("tomcat Rotate:"+admId);//S9Y qEERxxGVFo0DE8mruGVGmVYNJraVwZyijimEv6w=

    String url="http://localhost:8080/hello";
    UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromHttpUrl(url)
            .queryParam("admId", encode);
    String urls = uriComponentsBuilder.build().toUriString();

    HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(null, null);
    ResponseEntity<ResponsVO> response = restTemplate.exchange(urls, HttpMethod.GET, requestEntity,
            new ParameterizedTypeReference<ResponsVO>() {
            });

    return response.getBody().getData();
}

@GetMapping("hello")
public Object cdataDemo(String admId) throws Exception{
    
    System.out.println(admId);//S9Y qEERxxGVFo0DE8mruGVGmVYNJraVwZyijimEv6w=
    
    ResponsVO<Object> responsVO = new ResponsVO<>();
    responsVO.setCode(200);
    responsVO.setMsg("Success");
    User user = new User();
    user.setId(1);
    user.setName("Wang Zhenwei");
    responsVO.setData(user);
    return responsVO;
}

//Normal request we can see that the parameter admId turns into a space the first time it passes through tomcat, which is definitely incorrect

2. Second: Add transcode decoding

 @GetMapping("/cdata")
    public Object cdata(@RequestParam String admId) throws Exception{
        
        System.out.println("Before transcoding:"+admId);//Before transcoding: S9Y qEERxGVFo0DE8mruGVGmVYNJraVwZyijimEv6w=

        String encode = URLEncoder.encode(admId, "UTF-8");
        
        System.out.println("After transcoding:"+encode);//After transcoding: S9Y+qEERxGVFo0DE8mruGVGmVYNJraVwZyijimEv6w%3D

        String url="http://localhost:8080/hello";
        UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromHttpUrl(url)
                .queryParam("admId", encode);
        String urls = uriComponentsBuilder.build().toUriString();
        HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(null, null);
        ResponseEntity<ResponsVO> response = restTemplate.exchange(urls, HttpMethod.GET, requestEntity,
                new ParameterizedTypeReference<ResponsVO>() {
                });

        return response.getBody().getData();
    }

    @GetMapping("hello")
    public Object cdataDemo(String admId) throws Exception{
        
        System.out.println("Before decoding:"+admId);
        //Before decoding: S9Y qEERxGVFo0DE8mruGVGmVYNJraVwZyijimEv6w%3D
        System.out.println("After decoding:"+URLDecoder.decode(admId,"UTF-8"));
        //After decoding: S9Y qEERxGVFo0DE8mruGVGmVYNJraVwZyijimEv6w=
        
        ResponsVO<Object> responsVO = new ResponsVO<>();
        responsVO.setCode(200);
        responsVO.setMsg("Success");
        User user = new User();
        user.setId(1);
        user.setName("Wang Zhenwei");
        responsVO.setData(user);
        return responsVO;
    }
} 
/**
 * Before transcoding: S9Y qEERxGVFo0DE8mruGVGmVYNJraVwZyijimEv6w=
 * After transcoding: S9Y+qEERxGVFo0DE8mruGVGmVYNJraVwZyijimEv6w%3D
 * Before decoding: S9Y qEERxGVFo0DE8mruGVGmVYNJraVwZyijimEv6w%3D
 * After decoding: S9Y qEERxGVFo0DE8mruGVGmVYNJraVwZyijimEv6w=
 */
  • Still not, because admId has replaced'+'with a space after the first tomcat, and'=' has been converted to'%3D'as expected, but the space has been converted to'+', which is not what we expected'%20', which results in'+' being replaced with a space the second time the interface is requested.
  • Looking at this, is he not at a loss???

3. Third: Transcoding for front-end parameters - S9Y%2BqEERxGVFo0DE8mruGVGmVYNJraVwZyijimEv6w%3D

@GetMapping("/cdata")
    public Object cdata(@RequestParam String admId) throws Exception{
//        admId="admId%2BS9Y%2BqEERxxGVFo0DE8mruGVGmVYNJraVwZyijimEv6w%3D";
        
        System.out.println("Before transcoding:"+admId);//Before transcoding: S9Y+qEERxGVFo0DE8mruGVGmVYNJraVwZyijimEv6w=
        String encode = URLEncoder.encode(admId, "UTF-8");
        System.out.println("After transcoding:"+encode);//After transcoding: S9Y%2BqEERxGVFo0DE8mruGVmVYNJraVwZyijimEv6w%3D

        String url="http://localhost:8080/hello";
        UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromHttpUrl(url)
                .queryParam("admId", encode);
        String urls = uriComponentsBuilder.build().toUriString();
        HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(null, null);
        ResponseEntity<ResponsVO> response = restTemplate.exchange(urls, HttpMethod.GET, requestEntity,
                new ParameterizedTypeReference<ResponsVO>() {
                });

        return response.getBody().getData();
    }

    @GetMapping("hello")
    public Object cdataDemo(String admId) throws Exception{
        System.out.println("Before decoding:"+admId);
        //Before decoding: S9Y%2BqEERxGVFo0DE8mruGVGmVYNJraVwZyijimEv6w%3D
        System.out.println("After decoding:"+URLDecoder.decode(admId,"UTF-8"));
        //After decoding: S9Y+qEERxGVFo0DE8mruGVGmVYNJraVwZyijimEv6w=
        ResponsVO<Object> responsVO = new ResponsVO<>();
        responsVO.setCode(200);
        responsVO.setMsg("Success");
        User user = new User();
        user.setId(1);
        user.setName("Wang Zhenwei");
        responsVO.setData(user);
        return responsVO;
    }
/**
 * Before transcoding: S9Y+qEERxGVFo0DE8mruGVGmVYNJraVwZyijimEv6w=
 * After transcoding: S9Y%2BqEERxGVFo0DE8mruGVmVYNJraVwZyijimEv6w%3D
 * Before decoding: S9Y%2BqEERxGVFo0DE8mruGVGmVYNJraVwZyijimEv6w%3D
 * After decoding: S9Y+qEERxGVFo0DE8mruGVGmVYNJraVwZyijimEv6w=
 */
  • From the output, we can see that after the front-end transcodes the parameters,'+'is converted to'%2B' as expected, after tomcat decoding, it is transcoded, and after other service interfaces transcode it, normal data can be returned.
    3D
  • Before decoding: S9Y%2BqEERxGVFo0DE8mruGVGmVYNJraVwZyijimEv6w%3D
  • After decoding: S9Y+qEERxGVFo0DE8mruGVGmVYNJraVwZyijimEv6w=
    */
- From the output, we can see that after the front end transcodes the parameters, "+" Converted to "as expected"%2B",In tomcat After decoding, transcode it and return to normal data when it is docked by other service interfaces

Keywords: Java Network Protocol http

Added by Robert Elsdon on Sun, 26 Dec 2021 07:57:25 +0200