通过 REST 模板发送 json 文件时 415 不支持的媒体类型
415 Unsupported Media Type while sending json file over REST Template
我正在尝试通过 REST 模板发送 json 文件。当我通过 POST man 作为 MULTIPART_FORM_DATA 发送它时,它工作正常。我应该给出的名称是特定的(可以说 aaa)。附加屏幕截图 of POSTMAN. But when I try same in code as specified in another Whosebug 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]
因此,从服务器端日志中,我不确定内容类型添加为 application/octet-stream 的位置,因为我已将内容类型设置为
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 请求
- 客户端代码请求
有一件事我发现当我从 POST post 时,文件 iteam 的内容类型为 application/json当请求来自 客户端代码 .
时,MAN 并且内容类型为 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 在服务器端。file 只是任何时间的 文件 (image/text/pdf) 但是aaa是json数据文件)
再调试一点之后,我观察到服务器端控制器期望文件内容为 json,因为 Jackson 试图将 json 反序列化为 MyRequest 对象。当我从 POSTMAN 发送 post 时,它具有 json 内容,因此按预期工作,但从客户端代码来看,内容是 byteArray ,并且它没有反序列化为 MyRequest 对象。不确定如何解决这个问题
服务器端异常是由org.springframework.http.converter.json.MappingJackson2HttpMessageConverter
产生的。 Jackson 是一个 JSON 库,Spring 使用 MessageConverter 来格式化请求和响应。
难道客户端发送了一个"Accept: application/octet-stream",而服务器端却有一个@Produces(APPLICATION_JSON)注解?这将意味着服务器处理请求并且只在发送 响应 时遇到问题。您可以在服务器中添加一些 log.info() 语句来验证这一点。
我终于解决了这个问题。正如问题中提到的,在从 POSTMAN vs 代码发送请求时,具有不同内容类型的多部分文件是我开始的地方。如果有人有任何问题,我会详细解释。
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;
}
}
我正在尝试通过 REST 模板发送 json 文件。当我通过 POST man 作为 MULTIPART_FORM_DATA 发送它时,它工作正常。我应该给出的名称是特定的(可以说 aaa)。附加屏幕截图
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]
因此,从服务器端日志中,我不确定内容类型添加为 application/octet-stream 的位置,因为我已将内容类型设置为
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 请求
- 客户端代码请求
有一件事我发现当我从 POST post 时,文件 iteam 的内容类型为 application/json当请求来自 客户端代码 .
时,MAN 并且内容类型为 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 在服务器端。file 只是任何时间的 文件 (image/text/pdf) 但是aaa是json数据文件)
再调试一点之后,我观察到服务器端控制器期望文件内容为 json,因为 Jackson 试图将 json 反序列化为 MyRequest 对象。当我从 POSTMAN 发送 post 时,它具有 json 内容,因此按预期工作,但从客户端代码来看,内容是 byteArray ,并且它没有反序列化为 MyRequest 对象。不确定如何解决这个问题
服务器端异常是由org.springframework.http.converter.json.MappingJackson2HttpMessageConverter
产生的。 Jackson 是一个 JSON 库,Spring 使用 MessageConverter 来格式化请求和响应。
难道客户端发送了一个"Accept: application/octet-stream",而服务器端却有一个@Produces(APPLICATION_JSON)注解?这将意味着服务器处理请求并且只在发送 响应 时遇到问题。您可以在服务器中添加一些 log.info() 语句来验证这一点。
我终于解决了这个问题。正如问题中提到的,在从 POSTMAN vs 代码发送请求时,具有不同内容类型的多部分文件是我开始的地方。如果有人有任何问题,我会详细解释。
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;
}
}