Resttemplate上傳文件500異常的原因及解決方法
一、問題背景
使用 Resttemplate 調(diào)用 DMS 文件服務(wù)器 Http 接口,出現(xiàn) 500 異常報錯
二、問題描述
通過 ClientHttpRequestInterceptor 攔截器設(shè)置 ContentType 和 BasicAuth 后,調(diào)用DMS 文件服務(wù)器 Http 接口,出現(xiàn) 500 異常報錯
三、相關(guān)代碼
Resttemplate 及自定義 ClientHttpRequestInterceptor Bean 對象代碼
@Bean(name = "dmsRestTemplate") public RestTemplate restTemplate( @Qualifier("dmsRequestInterceptor") ClientHttpRequestInterceptor dmsRequestInterceptor) { RestTemplate restTemplate = new RestTemplate(); ((AllEncompassingFormHttpMessageConverter) restTemplate.getMessageConverters().get(4)) .setMultipartCharset(StandardCharsets.UTF_8); restTemplate.getInterceptors().add(dmsRequestInterceptor); restTemplate.setErrorHandler(new DefaultResponseErrorHandler() { @Override public boolean hasError(ClientHttpResponse response) throws IOException { return super.hasError(response.getStatusCode()) && !HttpStatus.NOT_FOUND.equals(response.getStatusCode()); } @Override public void handleError(ClientHttpResponse response) throws IOException { super.handleError(response); } }); return restTemplate; } @Bean public ClientHttpRequestInterceptor dmsRequestInterceptor(FileStorageProperties fileStorageProperties) { String userName = fileStorageProperties.getDms().getUserName(); String password = fileStorageProperties.getDms().getPassword(); return (request, body, execution) -> { HttpHeaders headers = request.getHeaders(); MediaType type = MediaType.parseMediaType(MediaType.MULTIPART_FORM_DATA_VALUE); headers.setContentType(type); headers.setBasicAuth(userName, password, StandardCharsets.UTF_8); return execution.execute(request, body); }; }
文件上傳代碼
@Override public FileStorageBO upload(String filePath) throws BaseAppException { LOGGER.debug("DMSFileStorage upload by file path start."); if (StringUtils.isEmpty(fileStorageProperties.getDms().getRestUrl())) { LOGGER.error("DMS rest url config not exist!"); ExceptionHandler.publish("EPA-COMMON-0010", ExceptionHandler.BUSS_ERROR); } File tempFile = new File(filePath); FileStorageBO result = new FileStorageBO(tempFile); MultiValueMap<String, Object> postParameters = new LinkedMultiValueMap<>(); FileSystemResource resource = new FileSystemResource(tempFile.getAbsolutePath()); postParameters.add("file", resource); postParameters.add("shardingkey", "EPA_" + getShardingKey()); HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(postParameters); try { String dmsId = dmsRestTemplate.postForObject(fileStorageProperties.getDms().getRestUrl() + "/file", httpEntity, String.class); result.setFileIdentity(dmsId); LOGGER.debug("DMSFileStorage upload by file path end. dms id is {}", dmsId); } catch (RestClientException e) { LOGGER.error(e); ExceptionHandler.publish("EPA-COMMON-0011", ExceptionHandler.BUSS_ERROR, e.getLocalizedMessage()); } return result; }
四、問題原因
攔截器中設(shè)置 ContentType 為 multipart/form-data 時,無法自動生成 boundary 信息,導(dǎo)致無法根據(jù)該分隔符信息來解析請求體
在使用multipart/form-data
格式發(fā)送HTTP請求時,請求體的數(shù)據(jù)會被分割成多個部分,每個部分之間使用一個特定的分隔符(boundary)進(jìn)行分隔。這個boundary是在Content-Type
頭部中指定的,用于告訴服務(wù)器如何識別每個部分的開始和結(jié)束。
當(dāng)使用RestTemplate
發(fā)送multipart/form-data
請求時,RestTemplate
會自動處理boundary的生成和添加到請求的Content-Type
頭部中。這樣服務(wù)器就能夠正確解析請求體中的各個部分。
使用RestTemplate
構(gòu)建multipart/form-data
請求時,只需設(shè)置正確的Content-Type
為multipart/form-data
,RestTemplate
會負(fù)責(zé)生成請求體的各個部分,并在Content-Type
頭部中添加正確的boundary
信息。
不需要手動追加boundary
到請求體中,RestTemplate
會在內(nèi)部處理這一細(xì)節(jié),確保請求能夠正確地被服務(wù)器解析。
因此,使用RestTemplate
發(fā)送multipart/form-data
請求時,只需設(shè)置正確的Content-Type
為multipart/form-data
,RestTemplate
會負(fù)責(zé)處理boundary
的生成和添加,確保請求能夠正確發(fā)送到服務(wù)器并被正確解析。
通常情況下,Content-Type
的設(shè)置應(yīng)該由發(fā)送請求的代碼負(fù)責(zé),而不是在ClientHttpRequestInterceptor
中進(jìn)行設(shè)置。ClientHttpRequestInterceptor
主要用于在發(fā)送請求之前或之后對請求進(jìn)行修改或處理,例如添加認(rèn)證信息、日志記錄、錯誤處理等。
五、問題修復(fù)
將 ContentType 移到上傳代碼中
攔截器 Bean:
@Bean public ClientHttpRequestInterceptor dmsRequestInterceptor(FileStorageProperties fileStorageProperties) { String userName = fileStorageProperties.getDms().getUserName(); String password = fileStorageProperties.getDms().getPassword(); return (request, body, execution) -> { HttpHeaders headers = request.getHeaders(); headers.setBasicAuth(userName, password, StandardCharsets.UTF_8); return execution.execute(request, body); }; }
上傳代碼:
@Override public FileStorageBO upload(String filePath) throws BaseAppException { LOGGER.debug("DMSFileStorage upload by file path start."); if (StringUtils.isEmpty(fileStorageProperties.getDms().getRestUrl())) { LOGGER.error("DMS rest url config not exist!"); ExceptionHandler.publish("EPA-COMMON-0010", ExceptionHandler.BUSS_ERROR); } File tempFile = new File(filePath); FileStorageBO result = new FileStorageBO(tempFile); MultiValueMap<String, Object> postParameters = new LinkedMultiValueMap<>(); FileSystemResource resource = new FileSystemResource(tempFile.getAbsolutePath()); postParameters.add("file", resource); postParameters.add("shardingkey", "EPA_" + getShardingKey()); HttpHeaders headers = new HttpHeaders(); MediaType type = MediaType.parseMediaType(MediaType.MULTIPART_FORM_DATA_VALUE); headers.setContentType(type); HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(postParameters, headers); try { String dmsId = dmsRestTemplate.postForObject(fileStorageProperties.getDms().getRestUrl() + "/file", httpEntity, String.class); result.setFileIdentity(dmsId); LOGGER.debug("DMSFileStorage upload by file path end. dms id is {}", dmsId); } catch (RestClientException e) { LOGGER.error(e); ExceptionHandler.publish("EPA-COMMON-0011", ExceptionHandler.BUSS_ERROR, e.getLocalizedMessage()); } return result; }
以上就是Resttemplate上傳文件500異常的原因及解決方法的詳細(xì)內(nèi)容,更多關(guān)于Resttemplate上傳文件500的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
基于Java語言在窗體上實現(xiàn)飛機(jī)大戰(zhàn)小游戲的完整步驟
這篇文章主要給大家介紹了基于Java語言在窗體上實現(xiàn)飛機(jī)大戰(zhàn)小游戲的完整步驟,文中通過圖文以及實例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2022-02-02Spring cloud Gateway簡介及相關(guān)配置方法
這篇文章主要介紹了Spring cloud Gateway簡介及相關(guān)配置方法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-04-04Java線程池的優(yōu)點(diǎn)及池化技術(shù)的應(yīng)用
這篇文章主要介紹了Java線程池的優(yōu)點(diǎn)及池化技術(shù)的應(yīng)用,Java種提高程序的執(zhí)行效率有兩種實現(xiàn)方法,一個是使用線程、另一個是使用線程池,下文我們就來具體介紹該詳細(xì)內(nèi)容吧,需要的小伙伴可以參考一下2022-05-05mybatisPlus如何使用MetaObjectHandler對字段進(jìn)行更新
這篇文章主要介紹了mybatisPlus如何使用MetaObjectHandler對字段進(jìn)行更新問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-04-04Java虛擬機(jī)JVM之server模式與client模式的區(qū)別
這篇文章主要介紹了Java虛擬機(jī)JVM的client模式和Server模式兩者的區(qū)別和聯(lián)系2017-12-12SpringBoot配置開發(fā)環(huán)境的詳細(xì)步驟(JDK、Maven、IDEA等)
文章介紹了如何配置SpringBoot開發(fā)環(huán)境,包括安裝JDK、Maven和IDEA,并提供了詳細(xì)的步驟和配置方法,感興趣的朋友一起看看吧2024-12-12Spring使用AspectJ的注解式實現(xiàn)AOP面向切面編程
這篇文章主要介紹了Spring使用AspectJ的注解式實現(xiàn)AOP面向切面編程的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-06-06zookeeper+Springboot實現(xiàn)服務(wù)器動態(tài)上下線監(jiān)聽教程詳解
這篇文章主要介紹了zookeeper+Springboot實現(xiàn)服務(wù)器動態(tài)上下線監(jiān)聽,主要介紹了什么是服務(wù)器動態(tài)上下線監(jiān)聽及為什么要實現(xiàn)對服務(wù)器上下線的監(jiān)聽,本文通過實例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-06-06