Spring 启动 & Jquery 415(不支持的媒体类型)
Spring boot & Jquery 415 (Unsupported Media Type)
我试图在安全上下文中对 spring 其余 Web 服务 api 进行 ajax 跨域 post 调用。
来自 Jquery 我无法设置 contentType 属性,因为我遇到了安全上下文问题。
但是如果没有来自 spring 的 contentType,我会收到以下响应:415(不支持的媒体类型)
Spring 控制器:
@RequestMapping(value = "/all", method = RequestMethod.POST)
@PreAuthorize("hasAnyAuthority('PROF1','SUDO')")
Jquery:
function getAllUsers(){
var obj = {"limit":10,"page":0};
$.ajax({
url:"https://webServerSite/myService/api/v1/user/all",
dataType: 'json',
xhrFields: {
withCredentials: true
},
crossDomain: true,
data:obj,
type: "post",
success:function(json){
var str = JSON.stringify(json);
console.log(str);
},
error:function(xhr, status, error) {
alert(xhr.responseText);
}
});
}
有一种方法可以禁用 Spring contentType 检查吗?
我所有的数据都是 json,我希望将其设置为默认值,避免 content-type header 检查。
我尝试定义自定义消息转换器,但使用以下代码无效:
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
//set path extension to true
configurer.favorPathExtension(true).
//set favor parameter to false
favorParameter(false).
//ignore the accept headers
ignoreAcceptHeader(true).
//dont use Java Activation Framework since we are manually specifying the mediatypes required below
useJaf(false).
defaultContentType(MediaType.APPLICATION_JSON).
mediaType("xml", MediaType.APPLICATION_XML).
mediaType("json", MediaType.APPLICATION_JSON);
}
谢谢
您可以使用带有 consumes
字段的 @RequestMapping
注释来指定您的控制器方法接受的内容类型。对于您的用例,您可能会考虑接受以下所有内容类型:
import org.springframework.http.MediaType;
@RequestMapping(value = "/all", method = RequestMethod.POST, consumes = {MediaType.ALL_VALUE})
更新:
您不应禁用 header 检查,否则,服务器不知道传入的内容类型以及如何正确解析它。
鉴于您的堆栈跟踪,我认为错误来自不同的来源。您尝试将传入的 application/x-www-form-urlencoded; charset=UTF-8
解析为 @RequestBody
,这对于 Spring 是不可能的。
此问题已在其他地方得到解答:Http Post request with content type application/x-www-form-urlencoded not working in Spring
我解决了在 spring 引导应用程序中添加以下转换器的问题:
import java.io.IOException;
import java.io.PushbackInputStream;
import java.lang.reflect.Type;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConversionException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.json.MappingJacksonInputMessage;
import org.springframework.lang.Nullable;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.exc.InvalidDefinitionException;
public class CustomMappingJackson2HttpMessageConverter extends AbstractJackson2HttpMessageConverter {
@Nullable
private String jsonPrefix;
public CustomMappingJackson2HttpMessageConverter() {
this(Jackson2ObjectMapperBuilder.json().build());
}
public CustomMappingJackson2HttpMessageConverter(ObjectMapper objectMapper) {
super(objectMapper, MediaType.APPLICATION_FORM_URLENCODED,MediaType.TEXT_PLAIN,MediaType.APPLICATION_JSON, new MediaType("application", "*+json"));
}
public void setJsonPrefix(String jsonPrefix) {
this.jsonPrefix = jsonPrefix;
}
public void setPrefixJson(boolean prefixJson) {
this.jsonPrefix = (prefixJson ? ")]}', " : null);
}
@Override
protected void writePrefix(JsonGenerator generator, Object object) throws IOException {
if (this.jsonPrefix != null) {
generator.writeRaw(this.jsonPrefix);
}
}
@Override
protected Object readInternal(Class<?> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {
JavaType javaType = getJavaType(clazz, null);
return readJavaType(javaType, inputMessage);
}
@Override
public Object read(Type type, @Nullable Class<?> contextClass, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {
JavaType javaType = getJavaType(type, contextClass);
return readJavaType(javaType, inputMessage);
}
private Object readJavaType(JavaType javaType, HttpInputMessage inputMessage) throws IOException {
try {
if (inputMessage instanceof MappingJacksonInputMessage) {
Class<?> deserializationView = ((MappingJacksonInputMessage) inputMessage).getDeserializationView();
if (deserializationView != null) {
return this.objectMapper.readerWithView(deserializationView).forType(javaType).
readValue(inputMessage.getBody());
}
}
PushbackInputStream pIs = new PushbackInputStream (inputMessage.getBody());
return this.objectMapper.readValue(pIs, javaType);
}
catch (InvalidDefinitionException ex) {
throw new HttpMessageConversionException("Type definition error: " + ex.getType(), ex);
}
catch (JsonProcessingException ex) {
throw new HttpMessageNotReadableException("JSON parse error: " + ex.getOriginalMessage(), ex, inputMessage);
}
}
}
在我的申请中:
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(customConverters());
}
public HttpMessageConverter customConverters() {
HttpMessageConverter<Object> converter = new CustomMappingJackson2HttpMessageConverter(new ObjectMapper());
return converter;
}
对于通过 siteminder 的跨域请求是必需的
我试图在安全上下文中对 spring 其余 Web 服务 api 进行 ajax 跨域 post 调用。 来自 Jquery 我无法设置 contentType 属性,因为我遇到了安全上下文问题。 但是如果没有来自 spring 的 contentType,我会收到以下响应:415(不支持的媒体类型)
Spring 控制器:
@RequestMapping(value = "/all", method = RequestMethod.POST)
@PreAuthorize("hasAnyAuthority('PROF1','SUDO')")
Jquery:
function getAllUsers(){
var obj = {"limit":10,"page":0};
$.ajax({
url:"https://webServerSite/myService/api/v1/user/all",
dataType: 'json',
xhrFields: {
withCredentials: true
},
crossDomain: true,
data:obj,
type: "post",
success:function(json){
var str = JSON.stringify(json);
console.log(str);
},
error:function(xhr, status, error) {
alert(xhr.responseText);
}
});
}
有一种方法可以禁用 Spring contentType 检查吗? 我所有的数据都是 json,我希望将其设置为默认值,避免 content-type header 检查。 我尝试定义自定义消息转换器,但使用以下代码无效:
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
//set path extension to true
configurer.favorPathExtension(true).
//set favor parameter to false
favorParameter(false).
//ignore the accept headers
ignoreAcceptHeader(true).
//dont use Java Activation Framework since we are manually specifying the mediatypes required below
useJaf(false).
defaultContentType(MediaType.APPLICATION_JSON).
mediaType("xml", MediaType.APPLICATION_XML).
mediaType("json", MediaType.APPLICATION_JSON);
}
谢谢
您可以使用带有 consumes
字段的 @RequestMapping
注释来指定您的控制器方法接受的内容类型。对于您的用例,您可能会考虑接受以下所有内容类型:
import org.springframework.http.MediaType;
@RequestMapping(value = "/all", method = RequestMethod.POST, consumes = {MediaType.ALL_VALUE})
更新:
您不应禁用 header 检查,否则,服务器不知道传入的内容类型以及如何正确解析它。
鉴于您的堆栈跟踪,我认为错误来自不同的来源。您尝试将传入的 application/x-www-form-urlencoded; charset=UTF-8
解析为 @RequestBody
,这对于 Spring 是不可能的。
此问题已在其他地方得到解答:Http Post request with content type application/x-www-form-urlencoded not working in Spring
我解决了在 spring 引导应用程序中添加以下转换器的问题:
import java.io.IOException;
import java.io.PushbackInputStream;
import java.lang.reflect.Type;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConversionException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.json.MappingJacksonInputMessage;
import org.springframework.lang.Nullable;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.exc.InvalidDefinitionException;
public class CustomMappingJackson2HttpMessageConverter extends AbstractJackson2HttpMessageConverter {
@Nullable
private String jsonPrefix;
public CustomMappingJackson2HttpMessageConverter() {
this(Jackson2ObjectMapperBuilder.json().build());
}
public CustomMappingJackson2HttpMessageConverter(ObjectMapper objectMapper) {
super(objectMapper, MediaType.APPLICATION_FORM_URLENCODED,MediaType.TEXT_PLAIN,MediaType.APPLICATION_JSON, new MediaType("application", "*+json"));
}
public void setJsonPrefix(String jsonPrefix) {
this.jsonPrefix = jsonPrefix;
}
public void setPrefixJson(boolean prefixJson) {
this.jsonPrefix = (prefixJson ? ")]}', " : null);
}
@Override
protected void writePrefix(JsonGenerator generator, Object object) throws IOException {
if (this.jsonPrefix != null) {
generator.writeRaw(this.jsonPrefix);
}
}
@Override
protected Object readInternal(Class<?> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {
JavaType javaType = getJavaType(clazz, null);
return readJavaType(javaType, inputMessage);
}
@Override
public Object read(Type type, @Nullable Class<?> contextClass, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {
JavaType javaType = getJavaType(type, contextClass);
return readJavaType(javaType, inputMessage);
}
private Object readJavaType(JavaType javaType, HttpInputMessage inputMessage) throws IOException {
try {
if (inputMessage instanceof MappingJacksonInputMessage) {
Class<?> deserializationView = ((MappingJacksonInputMessage) inputMessage).getDeserializationView();
if (deserializationView != null) {
return this.objectMapper.readerWithView(deserializationView).forType(javaType).
readValue(inputMessage.getBody());
}
}
PushbackInputStream pIs = new PushbackInputStream (inputMessage.getBody());
return this.objectMapper.readValue(pIs, javaType);
}
catch (InvalidDefinitionException ex) {
throw new HttpMessageConversionException("Type definition error: " + ex.getType(), ex);
}
catch (JsonProcessingException ex) {
throw new HttpMessageNotReadableException("JSON parse error: " + ex.getOriginalMessage(), ex, inputMessage);
}
}
}
在我的申请中:
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(customConverters());
}
public HttpMessageConverter customConverters() {
HttpMessageConverter<Object> converter = new CustomMappingJackson2HttpMessageConverter(new ObjectMapper());
return converter;
}
对于通过 siteminder 的跨域请求是必需的