resttemplate.exchange传递的param未在服务端自动解码

时间:2017-06-15 03:31:51

标签: spring-boot decode resttemplate

以下是我的REST API代码:

 @RequestMapping(value = "/get", method = RequestMethod.POST, produces = { "application/json" })
      @ApiOperation(value = "get data by key.", notes = "return json string value.")
      public JsonObjectResponse<String> get(
          @ApiParam(required = true, name = "regionName", value = "region name") @RequestParam("regionName") String regionName,
          @ApiParam(required = true, name = "key", value = "region key,Default is uuid") @RequestParam("key") String key) throws UnsupportedEncodingException
      {
        JsonObjectResponse<String> jr = new JsonObjectResponse<String>();
        //key = decodeJsonString(key);  // added for junit
        String val = adfService.onPath(regionName).get(key);
        jr.setState(StateCode.SUCCESS);
        jr.setData(JsonObject.create().append(key,val).toJson());

        return jr;
      }

我正在尝试传递参数:

regionName=/fusion/table1&key={"fusionTbl1DetailNo":"fusionNo001","pk":"PK0001"}
  1. 如果我通过swagger-ui调用它,它会这样调用:

    http://localhost:8080/service/basic/get?regionName=%2Ffusion%2Ftable1&key=%7B%22fusionTbl1DetailNo%22%3A%22fusionNo001%22%2C%22pk%22%3A%22PK0001%22%7D&token=8652493a-4147-43f4-af3a-bcb117fb7d42`
    

    它对参数进行了编码,这些参数也可以在服务器端自动解码。

  2. 当我想为此API添加测试用例时,我使用restTemplate.exchange方法,代码如下:

    UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url);
    for (Entry<String, String> entry : queryParamMap.entrySet()) {
        builder.queryParam(entry.getKey(), entry.getValue());
    }
    if (uriParamMap != null) {
    
        url = builder.buildAndExpand(uriParamMap).toUriString();
    } else {
        url = builder.toUriString();
    }
    if (StringUtils.isEmpty(requestBody)) {
        if (bodyParamMap != null) {
            requestBody = parseMapToParams(bodyParamMap);
        } else {
            requestBody = "";
        }
    }
    HttpHeaders headers = new HttpHeaders();
    MediaType mediaType = new MediaType("application", "json", Charset.forName("UTF-8"));
    headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
    // headers.add(HttpHeaders.CONTENT_TYPE, "application/json");
    // headers.add("Accept", "application/json");
    // headers.set(HttpHeaders.ACCEPT, "application/json");
    headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
    // headers.add("Accept-Encoding", "gzip, deflate, br");
    headers.set("Accept-Charset", "utf-8");
    headers.set("Accept-Encoding", "gzip");
    headers.add("Accept-Language", "zh-CN,zh;q=0.8,en;q=0.6");
    headers.add("User-Agent",
            "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36");
    
    headers.add(TestBase.TOKEN_HEADER, TestBase.getTokenId());
    HttpEntity<String> request = new HttpEntity<>(body, headers);
    restTemplate.getMessageConverters().add(0, new StringHttpMessageConverter(Charset.forName("UTF-8")));
    ResponseEntity<String> response = restTemplate.exchange(url, httpMethod, request, String.class);
    localresponse.set(response);
    System.out.println("response:" + response);
    return response;
    
  3. 我使用UriComponentsBuilder附加参数,它会将网址格式化为

    http://localhost:8080/service/basic/get?regionName=/fusion/table1&key=%7B%22fusionTbl1DetailNo%22:%22fusionNo001%22,%22pk%22:%22PK0001%22%7D
    
    方法exchange

    。但是,当服务器端收到呼叫时,它没有解码参数key,它的值仍然是:

    %7B%22fusionTbl1DetailNo%22:%22fusionNo001%22,%22pk%22:%22PK0001%22%7D
    

    为什么?我比较了swagger调用的标题设置,添加了额外的设置,没有效果:(。

3 个答案:

答案 0 :(得分:1)

尝试以下内容:

ResponseEntity<String> res = restTemplate.exchange("http://localhost:8080/service/basic/get?regionName={arg1}&key={arg2}", HttpMethod.POST, null, String.class,"/fusion/table1", "{\"fusionTbl1DetailNo\":\"fusionNo001\",\"pk\":\"PK0001\"}");

arg1arg2将替换为

"/fusion/table1""{\"fusionTbl1DetailNo\":\"fusionNo001\",\"pk\":\"PK0001\"}"

我在null中发送requestEntity,因为没有请求正文和请求参数在uriVariables中。

答案 1 :(得分:1)

RestTemplate上的Spring文档读取:

  

对于每个HTTP方法,有三种变体:两种接受URI   模板字符串和URI变量(数组或映射),而第三个接受   一个URI。请注意,对于URI模板,假设编码为   必要的,例如restTemplate.getForObject(&#34; http://example.com/hotel   list&#34;)成为&#34; http://example.com/hotel%20list&#34;。这也意味着   URI模板或URI变量已经编码,双重编码   会发生,

看起来你正在使用一个带有URI模板字符串的RestTemplate交换方法,因此你不应该对url-string进行编码。

首先在

上编码url-string
builder.toUriString()

然后又在交换电话上。所以问题似乎是客户端的双重编码,而不是服务器端的解码不足

答案 2 :(得分:1)

而不是toUriString()使用,UriComponentsBuilder.fromUriString(url).queryParam("name","John Doe").build().toString();