我正在尝试通过REST模板发送json文件。当我通过POST人以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
请不要将其标记为重复项,因为指定的答案对我不起作用。不共享代码,因为我的代码与this完全相同,除了
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]
因此,从服务器端日志中,由于将内容类型设置为
,因此我不确定在哪里将内容类型添加为应用程序/八位字节流。headers.setContentType(MediaType.MULTIPART_FORM_DATA);
下面是来自服务器控制器的代码。服务器端代码使用Spring Boot。
@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;
}
服务器代码具有拦截器,在这里我可以看到我的请求的内容类型为multipart / form-data。它没有到达RestController
在2种情况下调试服务器端代码时:
当我从 POSTMAN 发布时,我发现文件iteam的内容类型为 application / json ,而内容类型为 application / octet-stream (当请求来自客户端代码)时。
在我的客户端代码中,我将创建JSONObject为
JSONObject json = new JSONObject();
json.append("myKey", "myValue");
并将其转换为字节数组
json.toString().getBytes("UTF-8")
然后我遵循了this。我的代码不同之处在于,由于无法创建文件,我将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<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 ...
}
}
当我发送文件时,相同的代码也可以工作(注意 file 和 aaa 是两个不同的东西,尽管两者都是 multipart / form-data 服务器端。文件只是任何时间的文件(图像/文本/ pdf),但 aaa 是 json数据文件)
更多调试之后,我观察到服务器端控制器期望文件内容为json,因为Jackson尝试将该json反序列化为 MyRequest 对象。当我从POSTMAN发送帖子时,它具有json内容,可以正常工作,但是从客户端代码来看,该内容为 byteArray ,并且不会反序列化为 MyRequest 对象。不确定如何解决
答案 0 :(得分:1)
最后,我解决了这个问题。如前所述,从POSTMAN与代码发送请求时,具有不同内容类型的multipart文件是我的开始。如果有人有任何问题,我将详细解释。
public Optional<JSONObject> save(byte[] multipartFile, String fileName) {
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
Resource content = new MultipartByteArrayResource(multipartFile , fileName);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<Resource> requestEntityBody = new HttpEntity<Resource>(content, headers);
body.add("aaa", requestEntityBody);
String result = "";
JSONParser parser = new JSONParser();
JSONObject json = null;
HttpHeaders requestHeaders = new HttpHeaders();
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, requestHeaders);
ResponseEntity<String> 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<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
messageConverters.add(new FormHttpMessageConverter());
messageConverters.add(new StringHttpMessageConverter());
restTemplate.setMessageConverters(messageConverters);
return restTemplate;
}
}
答案 1 :(得分:0)
服务器端异常是由org.springframework.http.converter.json.MappingJackson2HttpMessageConverter
产生的。 Jackson是一个JSON库,Spring使用MessageConverter格式化请求和响应。
在服务器具有@Produces(APPLICATION_JSON)注释的同时,客户端是否可以发送“接受:应用程序/八位字节流”?这意味着服务器将处理请求,并且仅在发送响应时遇到问题。您可以在服务器中添加一些log.info()语句以进行验证。