您好,登錄后才能下訂單哦!
這篇文章主要介紹如何解決feign調用中文參數被encode編譯的問題,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!
在實現一個feign調用時使用了Post請求,并且拼接url參數,name傳值為中文時被encode轉譯,且最終接取數據之前未被decode轉譯回,問題探索:
feign:
@FeignClient(name = "service-test") public interface TestServiceApi { @PostMapping("/test/abc") public String getTestNo(@RequestParam("code") String code, @RequestParam("name") String name); }
controller:
@RequestMapping("/test") public interface TestController { @Autowired private TestService testService; @PostMapping("/abc") public String getTestNo(@RequestParam("code") String code, @RequestParam("name") String name) { return testService.query(code, name); } }
在controller中接到的中文參數被URIEncode轉譯了
測試 被轉譯成:%E6%B5%8B%E8%AF%95
找到feign的入口類ReflectiveFeign中拼裝RequestTemplate的方法:
@Override public RequestTemplate create(Object[] argv) { RequestTemplate mutable = new RequestTemplate(metadata.template()); if (metadata.urlIndex() != null) { int urlIndex = metadata.urlIndex(); checkArgument(argv[urlIndex] != null, "URI parameter %s was null", urlIndex); mutable.insert(0, String.valueOf(argv[urlIndex])); } Map<String, Object> varBuilder = new LinkedHashMap<String, Object>(); for (Entry<Integer, Collection<String>> entry : metadata.indexToName().entrySet()) { int i = entry.getKey(); Object value = argv[entry.getKey()]; if (value != null) { // Null values are skipped. if (indexToExpander.containsKey(i)) { value = expandElements(indexToExpander.get(i), value); } for (String name : entry.getValue()) { varBuilder.put(name, value); } } } // 組裝template的方法 RequestTemplate template = resolve(argv, mutable, varBuilder); if (metadata.queryMapIndex() != null) { // add query map parameters after initial resolve so that they take // precedence over any predefined values template = addQueryMapQueryParameters(argv, template); } if (metadata.headerMapIndex() != null) { template = addHeaderMapHeaders(argv, template); } return template; }
在RequestTemplate類中如果是拼接在url后的param那么會被使用encodeValueIfNotEncoded都encode轉譯,但是不會走decode的方法
/** * Resolves any template parameters in the requests path, query, or headers against the supplied * unencoded arguments. <br> <br><br><b>relationship to JAXRS 2.0</b><br> <br> This call is * similar to {@code javax.ws.rs.client.WebTarget.resolveTemplates(templateValues, true)} , except * that the template values apply to any part of the request, not just the URL */ RequestTemplate resolve(Map<String, ?> unencoded, Map<String, Boolean> alreadyEncoded) { replaceQueryValues(unencoded, alreadyEncoded); Map<String, String> encoded = new LinkedHashMap<String, String>(); for (Entry<String, ?> entry : unencoded.entrySet()) { final String key = entry.getKey(); final Object objectValue = entry.getValue(); String encodedValue = encodeValueIfNotEncoded(key, objectValue, alreadyEncoded); encoded.put(key, encodedValue); } String resolvedUrl = expand(url.toString(), encoded).replace("+", "%20"); if (decodeSlash) { resolvedUrl = resolvedUrl.replace("%2F", "/"); } url = new StringBuilder(resolvedUrl); Map<String, Collection<String>> resolvedHeaders = new LinkedHashMap<String, Collection<String>>(); for (String field : headers.keySet()) { Collection<String> resolvedValues = new ArrayList<String>(); for (String value : valuesOrEmpty(headers, field)) { String resolved = expand(value, unencoded); resolvedValues.add(resolved); } resolvedHeaders.put(field, resolvedValues); } headers.clear(); headers.putAll(resolvedHeaders); if (bodyTemplate != null) { body(urlDecode(expand(bodyTemplate, encoded))); } return this; }
如果傳入的值在requestBody中,則不會被encode轉譯
@Override public void encode(Object requestBody, Type bodyType, RequestTemplate request) throws EncodeException { // template.body(conversionService.convert(object, String.class)); if (requestBody != null) { Class<?> requestType = requestBody.getClass(); Collection<String> contentTypes = request.headers().get("Content-Type"); MediaType requestContentType = null; if (contentTypes != null && !contentTypes.isEmpty()) { String type = contentTypes.iterator().next(); requestContentType = MediaType.valueOf(type); } for (HttpMessageConverter<?> messageConverter : this.messageConverters .getObject().getConverters()) { if (messageConverter.canWrite(requestType, requestContentType)) { if (log.isDebugEnabled()) { if (requestContentType != null) { log.debug("Writing [" + requestBody + "] as \"" + requestContentType + "\" using [" + messageConverter + "]"); } else { log.debug("Writing [" + requestBody + "] using [" + messageConverter + "]"); } } FeignOutputMessage outputMessage = new FeignOutputMessage(request); try { @SuppressWarnings("unchecked") HttpMessageConverter<Object> copy = (HttpMessageConverter<Object>) messageConverter; copy.write(requestBody, requestContentType, outputMessage); } catch (IOException ex) { throw new EncodeException("Error converting request body", ex); } // clear headers request.headers(null); // converters can modify headers, so update the request // with the modified headers request.headers(getHeaders(outputMessage.getHeaders())); // do not use charset for binary data if (messageConverter instanceof ByteArrayHttpMessageConverter) { request.body(outputMessage.getOutputStream().toByteArray(), null); } else { request.body(outputMessage.getOutputStream().toByteArray(), Charset.forName("UTF-8")); } return; } } String message = "Could not write request: no suitable HttpMessageConverter " + "found for request type [" + requestType.getName() + "]"; if (requestContentType != null) { message += " and content type [" + requestContentType + "]"; } throw new EncodeException(message); } }
綜合上述的調試,如果在Post中拼接參數那么會被encode轉譯,且不會被decode轉譯,如果使用body傳參,那么不會出現轉譯問題,如果必須使用拼接傳參,那么可以使用方法
1. @RequestLine的注解自定義參數的格式,具體參考該注解的使用方式。
2.在Feign的RequestInterceptor將傳遞的值decode的擴展方法。
錯誤寫法示例如下:
public int save(@RequestBody final User u, @RequestBody final School s);
錯誤原因:
fegin中可以有多個@RequestParam,但只能有不超過一個@RequestBody,@RequestBody用來修飾對象,但是既有@RequestBody也有@RequestParam,
那么參數就要放在請求的Url中,@RequestBody修飾的就要放在提交對象中。
注意!!! 用來處理@RequestBody Content-Type 為 application/json,application/xml編碼的內容
正確寫法示例如下:
public int save(@RequestBody final Person p,@RequestParam("userId") String userId,@RequestParam("userTel") String userTel);
錯誤寫法示例如下:
@RequestMapping(value="/test", method=RequestMethod.GET) Model test(final String name, final int age);
錯誤原因:
異常原因:當使用Feign時,如果發送的是get請求,那么需要在請求參數前加上@RequestParam注解修飾,Controller里面可以不加該注解修飾,@RequestParam可以修飾多個,@RequestParam是用來修飾參數,不能用來修飾整個對象。
注意:@RequestParam Content-Type 為 application/x-www-form-urlencoded 而這種是默認的
正確寫法示例如下:
@GetMapping("/getSchoolDetail") public ResultMap getSchoolDetail(@RequestParam("kSchoolId") LongkSchoolId, @RequestParam("kSchoolYearId") Long kSchoolYearId);
以上是“如何解決feign調用中文參數被encode編譯的問題”這篇文章的所有內容,感謝各位的閱讀!希望分享的內容對大家有幫助,更多相關知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。