Я пытаюсь отправить список файлов с помощью Spring Rest, но я получаю это исключение.
Could not write content: No serializer found for class java.io.ByteArrayInputStream
Он работает с одним файлом (ByteArrayResource
).
Он не работает со списком файлов (List<ByteArrayResource>
).
Вот важные части моего кода:
List<ByteArrayResource> contentsAsResource = new ArrayList<ByteArrayResource>();
for(MultipartFile fichier : fichiers) {
contentsAsResource.add(new ByteArrayResource(fichier.getBytes()) {
@Override
public String getFilename()
{
return fichier.getOriginalFilename();
}
});
};
map.add("files", contentsAsResource);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
HttpEntity<LinkedMultiValueMap<String, Object>> requestEntity = new HttpEntity<LinkedMultiValueMap<String, Object>>(map, headers);
FormHttpMessageConverter formConverter = new FormHttpMessageConverter();
formConverter.setMultipartCharset(Charset.forName("UTF8"));
formConverter.addPartConverter(new MappingJackson2HttpMessageConverter());
this.restClientHelper.getRestTemplate().getMessageConverters().add(formConverter);
this.restClientHelper.getRestTemplate().postForObject("file/save", requestEntity, Object.class);
Я пробовал следующее, которое не срабатывало:
- отправить массив вместо списка
- обернуть список в dto
- отправить байты [], но он не работает, когда файл > 1.5Mb
Я отлаживал десериализацию, но это такая боль, чтобы понять!
Если это может помочь, с одним файлом используется конвертер ResourceHttpMessageConverter
.
У кого-нибудь есть идея?
EDIT: запрос работает, если я добавляю каждый файл по файлу на карте (вместо списка).
for (MultipartFile fichier : fichiers) {
map.add("files", new ByteArrayResource(fichier.getBytes()) {
@Override
public String getFilename()
{
return fichier.getOriginalFilename();
}
});
};
но я получаю другое исключение: org.springframework.web.client.ResourceAccessException: I/O error on POST request for "http://localhost:8080/myApp/ws/file/save"
. На целевом сервере включена базовая аутентификация. Если я отключил его, все работает! Вот конфигурация spring -security на целевом сервере.
<http pattern="/ws/file/**" authentication-manager-ref="basicAuthenticationManager" create-session="stateless">
<intercept-url pattern="/**" access="isAuthenticated()"/>
<http-basic />
<csrf disabled="true" />
<headers disabled="true" />
</http>
Я что-то упустил в конфигурации безопасности Spring?
ИЗМЕНИТЬ 2: похоже, в заголовках нет токена "Авторизация", добавив его вручную, исправить проблему
ИЗМЕНИТЬ 3: Проблема решена! При отправке многократных файлов с шаблоном отдыха Spring на целевой сервер с включенным базовым авторизацией необходимо (re) добавить базовый токен аутентификации. Здесь хорошо объяснено: Базовая аутентификация для REST API с помощью Spring restTemplate. Я не знаю, была ли это ошибка или нет (от Spring). Моя конфигурация перед этим обновлением (я выбрал путь перехватчика):
final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(login, motDePasse));
httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
...
final HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(httpClientBuilder.build());
this.restTemplate = new RestTemplate(requestFactory);
Я добавил следующее:
this.restTemplate.getInterceptors().add(new BasicAuthorizationInterceptor(username, password));
Класс:
private static class BasicAuthorizationInterceptor implements ClientHttpRequestInterceptor
{
private final String username;
private final String password;
public BasicAuthorizationInterceptor(String username, String password)
{
this.username = username;
this.password = (password == null ? "" : password);
}
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException
{
byte[] token = Base64.getEncoder().encode((this.username + ":" + this.password).getBytes());
request.getHeaders().add("Authorization", "Basic " + new String(token));
return execution.execute(request, body);
}
}