415 Tipo de mídia não suportado ao enviar o arquivo json pelo modelo REST
Estou tentando enviar um arquivo json sobre o modelo REST. Quando o envio via POST man como MULTIPART_FORM_DATA, ele funciona bem. O nome que devo dar é específico (digamosaaa) Captura de tela anexadado POSTMAN. Mas quando tento o mesmo no código especificado em outro stackoverflowpostar, Recebo o erro 415 Tipo de mídia não suportado como
org.springframework.web.client.HttpClientErrorException: 415 Unsupported Media Type
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:91) ~[spring-web-4.1.9.RELEASE.jar:4.1.9.RELEASE]
at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:616) ~[spring-web-4.1.9.RELEASE.jar:4.1.9.RELEASE]
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:572) ~[spring-web-4.1.9.RELEASE.jar:4.1.9.RELEASE]
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:532) ~[spring-web-4.1.9.RELEASE.jar:4.1.9.RELEASE]
at org.springframework.web.client.RestTemplate.postForObject(RestTemplate.java:332) ~[spring-web-4.1.9.RELEASE.jar:4.1.9.RELEASE]
at
Não marque-o como duplicado, pois a resposta especificada não funcionou para mim. Não compartilhar código, pois meu código é exatamente o mesmo queesta exceto
requestParamerterMap.add("attachment", resource);
onde como meu código é
requestParamerterMap.add("aaa", resource);
Após a depuração do lado do servidor, parece que a solicitação está chegando ao servidor. Consegui ver abaixo o erro no lado do servidor:
[{error=Unsupported Media Type, exception=org.springframework.web.HttpMediaTypeNotSupportedException, message=Content type 'application/octet-stream' not supported, status=415, timestamp=1532557180124}] as "application/json" using [org.springframework.http.converter.json.MappingJackson2HttpMessageConverter@74d4827a]
Portanto, nos logs do lado do servidor, não tenho certeza de onde o tipo de conteúdo está sendo adicionado como application / octet-stream, pois configurei o tipo de conteúdo como
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
Abaixo está o código do controlador do servidor. O código do lado do servidor usa a inicialização do Spring.
@RequestMapping(method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE,consumes = {"multipart/form-data"})
@ResponseBody
public MyResponse uploadPhoto(@RequestPart(value = "aaa", required = false) Optional<MyRequest> myRequest,
@RequestPart(value = "file", required = false) Optional<MultipartFile> file,
HttpServletRequest request) {
//some logic
return myResponse;
}
O código do servidor possui um interceptador, no qual posso ver que minha solicitação possui um tipo de conteúdo como multipart / form-data. Não chega ao RestController
Quando depurei o código do lado do servidor em 2 casos:
Solicitação POSTMANsolicitação de código do clienteUma coisa que eu descobri que o arquivo iteam tem o tipo de conteúdo comoapplication / json quando eu postar deCARTEIRO e o tipo de conteúdo eraapplication / octet-stream quando a solicitação vai decódigo do lado do cliente.
No meu código do lado do cliente, estou criando JSONObject como
JSONObject json = new JSONObject();
json.append("myKey", "myValue");
e convertê-lo em matriz de bytes como
json.toString().getBytes("UTF-8")
então eu seguiesta . A diferença no meu código é que estou enviando meu JSONObject como fluxo de bytes, pois não consigo criar arquivo (problemas de desempenho).
E não posso enviar JSONObject como string, pois o servidor espera dados de várias partes do formulário paraarquivo e aaa
Eu criei o restTemplate como
public RestTemplate myRestTemplate() {
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setReadTimeout(HTTP_CLIENT_TIMEOUT);
requestFactory.setConnectTimeout(HTTP_CLIENT_TIMEOUT);
RestTemplate restTemplate = new RestTemplate(requestFactory);
List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
messageConverters.add(new FormHttpMessageConverter());
messageConverters.add(new StringHttpMessageConverter());
restTemplate.setMessageConverters(messageConverters);
return restTemplate;
Aqui está o código do lado do cliente que chama o serviço:
public Optional<JSONObject> callService(byte[] multipartFile) {
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
InputStream stream = new ByteArrayInputStream(multipartFile);
MultipartByteArrayResource resource = new MultipartByteArrayResource(multipartFile,fileName);
body.add("aaa", resource);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);
try {
response = restTemplate.postForObject(url, requestEntity , String.class);
} catch (Exception exception) {
LOG.error("Error", exception);
return Optional.empty();
}
}
public class MultipartInputStreamFileResource extends InputStreamResource {
private final String filename;
MultipartInputStreamFileResource(InputStream inputStream, String filename) {
super(inputStream);
this.filename = filename;
}
@Override
public String getFilename() {
return this.filename;
}
@Override
public long contentLength() throws IOException {
return -1; // we do not want to generally read the whole stream into memory ...
}
}
E o mesmo código funciona quando eu envio um arquivo (noteArquivo eaaa Existem duas coisas diferentes, embora ambas sejammultipart / form-data no lado do servidor.Arquivo é apenas umarquivo a qualquer momento (imagem / texto / pdf) masaaa éarquivo de dados json)
Depois de depurar um pouco mais, o que observei é que o controlador do servidor espera que o conteúdo do arquivo seja json enquanto Jackson tenta desserializar esse json paraMeu pedido objeto. Quando envio uma postagem do POSTMAN, ele possui o conteúdo json funcionando conforme o esperado, mas a partir do código do lado do cliente, o conteúdo ébyteArraye não está sendo desserializado paraMeu pedido objeto. Não tenho certeza de como consertar isso