415通过REST模板发送json文件时不支持的媒体类型
我试图通过REST模板发送一个json文件。 当我通过POST man发送它作为MULTIPART_FORM_DATA时,它工作正常。 我应该给出的名称是具体的(比方说aaa )。 附上截图 POSTMAN。 但是当我在另一个stackoverflow post中指定的代码中尝试相同时,我得到415 Unsupported Media Type错误
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
请不要将其标记为重复,因为指定的答案对我不起作用。 不共享代码,因为我的代码与此完全相同,除了
requestParamerterMap.add("attachment", resource);
我的代码在哪里
requestParamerterMap.add("aaa", resource);
从服务器端调试后,看起来请求正在向服务器伸出。 我能够在服务器端看到以下错误:
[{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]
所以,从服务器端日志,我不知道内容类型在哪里被添加为application / octet-stream,因为我已将内容类型设置为
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
以下是服务器控制器的代码。 服务器端代码使用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, @RequestPart(value = "file", required = false) Optional file, HttpServletRequest request) { //some logic return myResponse; }
服务器代码有一个拦截器,我可以看到我的请求的内容类型为multipart / form-data。 它没有到达RestController
当我在2种情况下调试服务器端代码时:
- POSTMAN请求
- 客户端代码请求
有一件事我发现,当我从POSTMAN发帖时,文件iteam的内容类型为application / json,当请求来自客户端代码时,内容类型是application / octet-stream 。
在我的客户端代码中,我正在创建JSONObject
JSONObject json = new JSONObject(); json.append("myKey", "myValue");
并将其转换为字节数组
json.toString().getBytes("UTF-8")
然后我跟着这个 。 我的代码的不同之处在于,我将JSONObject作为字节流发送,因为我无法创建文件(性能问题)。
我不能将JSONObject作为字符串发送,因为服务器期望文件和aaa的多部分表单数据
我已经创建了restTemplate
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;
以下是调用服务的客户端代码:
public Optional callService(byte[] multipartFile) { MultiValueMap 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> 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 ... } }
当我发送文件时,相同的代码工作(注释文件和aaa是两个不同的东西,虽然两者都是服务器端的multipart / form-data 。 文件只是一个任何时间的文件(image / text / pdf)但是aaa是json数据文件 )
经过多次调试后,我观察到的是服务器端控制器期望文件内容为json,因为Jackson尝试将该json反序列化为MyRequest对象。 当我从POSTMAN发送post时,它的json内容如此按预期工作,但是从客户端代码,内容是byteArray ,并且它没有反序列化到MyRequest对象。 不知道如何解决这个问题
最后我解决了这个问题。 如上所述,从POSTMAN到代码发送请求时,具有不同内容类型的多部分文件是我开始的地方。 如果有人有任何问题,我会详细解释。
public Optional save(byte[] multipartFile, String fileName) { MultiValueMap body = new LinkedMultiValueMap<>(); Resource content = new MultipartByteArrayResource(multipartFile , fileName); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); HttpEntity requestEntityBody = new HttpEntity (content, headers); body.add("aaa", requestEntityBody); String result = ""; JSONParser parser = new JSONParser(); JSONObject json = null; HttpHeaders requestHeaders = new HttpHeaders(); HttpEntity> requestEntity = new HttpEntity<>(body, requestHeaders); ResponseEntity response = null; try { RestTemplate restTemplate = customizeRestTemplate(); //I have defined this in different config file in my actual code response = restTemplate.exchange(url , HttpMethod.POST , requestEntity , String.class); result = (response != null && response.getBody() != null) ? response.getBody().toString() : result; json = (JSONObject) parser.parse(result); LOG.info( "Response:", response ); } catch (Exception exception) { LOG.error("Error , exception); return Optional.empty(); } return Optional.ofNullable(json); } public class MultipartByteArrayResource extends ByteArrayResource{ private String fileName; public MultipartByteArrayResource(byte[] byteArray , String filename) { super(byteArray); this.fileName = filename; } public String getFilename() { return fileName; } public void setFilename(String fileName) { this.fileName= fileName; } } public RestTemplate customizeRestTemplate() { SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory(); requestFactory.setReadTimeout(10000); requestFactory.setConnectTimeout(10000); RestTemplate restTemplate = new RestTemplate(requestFactory); List> messageConverters = new ArrayList>(); messageConverters.add(new FormHttpMessageConverter()); messageConverters.add(new StringHttpMessageConverter()); restTemplate.setMessageConverters(messageConverters); return restTemplate; } }
服务器端exception由org.springframework.http.converter.json.MappingJackson2HttpMessageConverter
。 Jackson是一个JSON库,Spring使用MessageConverter来格式化请求和响应。
当服务器有@Produces(APPLICATION_JSON)注释时,客户端是否可以发送“Accept:application / octet-stream”? 这意味着服务器处理请求并且仅在发送响应时出现问题。 您可以在服务器中添加一些log.info()语句来validation这一点。