• 作者:老汪软件技巧
  • 发表时间:2024-08-23 00:02
  • 浏览量:

三、相关代码

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 postParameters = new LinkedMultiValueMap<>();
    FileSystemResource resource = new FileSystemResource(tempFile.getAbsolutePath());
    postParameters.add("file", resource);
    postParameters.add("shardingkey", "EPA_" + getShardingKey());
    HttpEntity> 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;
}

四、问题原因

拦截器中设置 ContentType 为 multipart/form-data 时,无法自动生成 boundary 信息,导致无法根据该分隔符信息来解析请求体

在使用multipart/form-data格式发送HTTP请求时,请求体的数据会被分割成多个部分,每个部分之间使用一个特定的分隔符(boundary)进行分隔。这个boundary是在Content-Type头部中指定的,用于告诉服务器如何识别每个部分的开始和结束。

当使用RestTemplate发送multipart/form-data请求时,RestTemplate会自动处理boundary的生成和添加到请求的Content-Type头部中。这样服务器就能够正确解析请求体中的各个部分。

上传文件异常什么意思_上传文件报错_

使用RestTemplate构建multipart/form-data请求时,只需设置正确的Content-Type为multipart/form-data,RestTemplate会负责生成请求体的各个部分,并在Content-Type头部中添加正确的boundary信息。

不需要手动追加boundary到请求体中,RestTemplate会在内部处理这一细节,确保请求能够正确地被服务器解析。

因此,使用RestTemplate发送multipart/form-data请求时,只需设置正确的Content-Type为multipart/form-data,RestTemplate会负责处理boundary的生成和添加,确保请求能够正确发送到服务器并被正确解析。

通常情况下,Content-Type的设置应该由发送请求的代码负责,而不是在ClientHttpRequestInterceptor中进行设置。ClientHttpRequestInterceptor主要用于在发送请求之前或之后对请求进行修改或处理,例如添加认证信息、日志记录、错误处理等。

六、问题修复

将 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 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> 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;
}