您好,登錄后才能下訂單哦!
在實際項目中,對傳入的圖片url進行下載,使用的是RestTemplate的exchange方法,具體如下:
使用以下RestTemplate的方法:
Sring url = "http://10.64.203.183:6120/pic?=d6ei2a4i9c84*33c-793=11i5m*ep5t9d5=*2pdi=*1s5i2=94b8i5d2e*14b863328-aa2e959-1b246b-43s=10d3z83";
ResponseEntity<byte[]> responseEntity = restTemplate
.exchange(url, HttpMethod.GET, null, byte[].class);
用這種方式調用請求,抓拍可看出url中的特殊字符被轉義:
http://10.64.203.183:6120/pic?d6ei2a4i9c84*33c-793=11i5m*ep5t9d5%3D*2pdi%3D*1s5i2%3D94b8i5d2e*14b863328-aa2e959-1b246b-43s%3D10d3z83
由于第三方的圖片服務器,沒有對請求的url進行解碼,因此不識別轉義后的url導致下載失敗。
如果不希望被轉碼,則可使用
public <T> ResponseEntity<T> exchange(URI url, HttpMethod method, @Nullable HttpEntity<?> requestEntity, Class<T> responseType)
該方法,直接傳入URI對象。
該對象可如下進行組裝:
Sring url = "http://10.64.203.183:6120/pic?=d6ei2a4i9c84*33c-793=11i5m*ep5t9d5=*2pdi=*1s5i2=94b8i5d2e*14b863328-aa2e959-1b246b-43s=10d3z83";
URI uri = new URI(url);
restTemplate.exchange(url, HttpMethod.GET, null, byte[].class);
這樣,url就不會被encode成utf-8,不會將特殊字符轉義,解決了下載失敗的問題。
以下是url被轉碼的源碼分析。
對應的包為
Sring url = "http://10.64.203.183:6120/pic?=d6ei2a4i9c84*33c-793=11i5m*ep5t9d5=*2pdi=*1s5i2=94b8i5d2e*14b863328-aa2e959-1b246b-43s=10d3z83";
ResponseEntity<byte[]> responseEntity = restTemplate
.exchange(url, HttpMethod.GET, null, byte[].class);
對應源碼的調用關系:
RestTemplate.class:
public <T> ResponseEntity<T> exchange(String url, HttpMethod method, @Nullable HttpEntity<?> requestEntity, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException {
RequestCallback requestCallback = this.httpEntityCallback(requestEntity, responseType);
ResponseExtractor<ResponseEntity<T>> responseExtractor = this.responseEntityExtractor(responseType);
return (ResponseEntity)nonNull(this.execute(url, method, requestCallback, responseExtractor, uriVariables));
}
RestTemplate.class:
@Nullable
public <T> T execute(String url, HttpMethod method, @Nullable RequestCallback requestCallback, @Nullable ResponseExtractor<T> responseExtractor, Map<String, ?> uriVariables) throws RestClientException {
URI expanded = this.getUriTemplateHandler().expand(url, uriVariables);
return this.doExecute(expanded, method, requestCallback, responseExtractor);
}
從execute函數可看出,源碼中會將url String對象轉成URI對象。
轉換的源碼如下:
DefaultUriBuilderFactory.class:
public URI expand(String uriTemplate, Map<String, ?> uriVars) {
return this.uriString(uriTemplate).build(uriVars);
}
我們來看下this.uriString(uriTemplate),返回的是UriBuilder 對象,
public UriBuilder uriString(String uriTemplate) {
return new DefaultUriBuilderFactory.DefaultUriBuilder(uriTemplate);
}
private class DefaultUriBuilder implements UriBuilder:
public DefaultUriBuilder(String uriTemplate) {
this.uriComponentsBuilder = this.initUriComponentsBuilder(uriTemplate);
}
private UriComponentsBuilder initUriComponentsBuilder(String uriTemplate) {
UriComponentsBuilder result;
if (!StringUtils.hasLength(uriTemplate)) {
result = DefaultUriBuilderFactory.this.baseUri != null ? DefaultUriBuilderFactory.this.baseUri.cloneBuilder() : UriComponentsBuilder.newInstance();
} else if (DefaultUriBuilderFactory.this.baseUri != null) {
UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(uriTemplate);
UriComponents uri = builder.build();
result = uri.getHost() == null ? DefaultUriBuilderFactory.this.baseUri.cloneBuilder().uriComponents(uri) : builder;
} else {
result = UriComponentsBuilder.fromUriString(uriTemplate);
}
if (DefaultUriBuilderFactory.this.encodingMode.equals(DefaultUriBuilderFactory.EncodingMode.TEMPLATE_AND_VALUES)) {
result.encode();
}
this.parsePathIfNecessary(result);
return result;
}
result.encode();該語句設置了該對象編碼格式:
UriComponentsBuilder.class
public final UriComponentsBuilder encode() {
return this.encode(StandardCharsets.UTF_8);
}
public UriComponentsBuilder encode(Charset charset) {
this.encodeTemplate = true;
this.charset = charset;
return this;
}
至此,獲取到一個UriBuilder對象,且該對象中的charset設置成utf-8。
以上代碼,我們解釋到了this.uriString(uriTemplate),返回的是UriBuilder 對象,接下來我們看this.uriString(uriTemplate).build(uriVars)中build(uriVars)。
UriComponentsBuilder.class
public URI build(Map<String, ?> uriVariables) {
return this.buildInternal(UriComponentsBuilder.EncodingHint.ENCODE_TEMPLATE).expand(uriVariables).toUri();
}
/**
被上以函數調用,傳入的hint是UriComponentsBuilder.EncodingHint.ENCODE_TEMPLATE
*/
private UriComponents buildInternal(UriComponentsBuilder.EncodingHint hint) {
Object result;
if (this.ssp != null) {
result = new OpaqueUriComponents(this.scheme, this.ssp, this.fragment);
} else {
//走到該邏輯
HierarchicalUriComponents uric = new HierarchicalUriComponents(this.scheme, this.fragment, this.userInfo, this.host, this.port, this.pathBuilder.build(), this.queryParams, hint == UriComponentsBuilder.EncodingHint.FULLY_ENCODED);
//下面的判斷為真,因此result賦值為uric.encodeTemplate(this.charset),其中this.charset在上面已被設置成utf-8
result = hint == UriComponentsBuilder.EncodingHint.ENCODE_TEMPLATE ? uric.encodeTemplate(this.charset) : uric;
}
if (!this.uriVariables.isEmpty()) {
result = ((UriComponents)result).expand((name) -> {
return this.uriVariables.getOrDefault(name, UriTemplateVariables.SKIP_VALUE);
});
}
return (UriComponents)result;
}
HierarchicalUriComponents.class
/**
該對象將對象中的內容均進行utf-8編碼
*/
HierarchicalUriComponents encodeTemplate(Charset charset) {
if (this.encodeState.isEncoded()) {
return this;
} else {
this.variableEncoder = (value) -> {
return encodeUriComponent(value, charset, HierarchicalUriComponents.Type.URI);
};
HierarchicalUriComponents.UriTemplateEncoder encoder = new HierarchicalUriComponents.UriTemplateEncoder(charset);
String schemeTo = this.getScheme() != null ? encoder.apply(this.getScheme(), HierarchicalUriComponents.Type.SCHEME) : null;
String fragmentTo = this.getFragment() != null ? encoder.apply(this.getFragment(), HierarchicalUriComponents.Type.FRAGMENT) : null;
String userInfoTo = this.getUserInfo() != null ? encoder.apply(this.getUserInfo(), HierarchicalUriComponents.Type.USER_INFO) : null;
String hostTo = this.getHost() != null ? encoder.apply(this.getHost(), this.getHostType()) : null;
HierarchicalUriComponents.PathComponent pathTo = this.path.encode(encoder);
MultiValueMap<String, String> queryParamsTo = this.encodeQueryParams(encoder);
return new HierarchicalUriComponents(schemeTo, fragmentTo, userInfoTo, hostTo, this.port, pathTo, queryParamsTo, HierarchicalUriComponents.EncodeState.TEMPLATE_ENCODED, this.variableEncoder);
}
}
如上,因此調用RestTemplate類的public <T> ResponseEntity<T> exchange(String url, HttpMethod method, @Nullable HttpEntity<?> requestEntity, Class<T> responseType)函數,傳入的url會被轉碼成utf-8。
這樣,傳輸過程中特殊字符就不會被轉義
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。