【问题标题】:Spring boot & Jquery 415 (Unsupported Media Type)Spring boot & Jquery 415(不支持的媒体类型)
【发布时间】:2020-06-26 06:13:58
【问题描述】:

我尝试在安全上下文中对 Spring Rest Web 服务 API 进行 ajax 跨域发布调用。 从 Jquery 我无法设置 contentType 属性 cos 然后我遇到了安全上下文的问题。 但是如果没有 spring 的 contentType,我会收到以下响应:415 (Unsupported Media Type)

弹簧控制器:

@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,我希望将其设置为默认值,以避免内容类型标头检查。 我尝试定义一个自定义消息转换器并使用以下代码不起作用:

@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);
      }

谢谢

【问题讨论】:

    标签: jquery ajax spring-boot rest cross-domain


    【解决方案1】:

    您可以使用带有consumes 字段的@RequestMapping 注释来指定您的控制器方法接受的内容类型。对于您的用例,您可以考虑接受以下所有内容类型:

    import org.springframework.http.MediaType;
    
    @RequestMapping(value = "/all", method = RequestMethod.POST, consumes = {MediaType.ALL_VALUE})
    

    更新

    您不应该禁用标头检查,否则服务器不知道传入的内容类型以及如何正确解析它。

    鉴于您的堆栈跟踪,我认为错误来自不同的来源。您尝试将传入的 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

    【讨论】:

    • 嗨 rieckpil,感谢您的回复。我像你说的那样尝试,但我也收到了 spring 的 415 响应
    • 当您向后端发出 HTTP 请求并发布所有 requets 标头时,您能否检查浏览器中的网络选项卡?
    • 嗨 rieckpil,这里的标头请求: Content-Type: application/x-www-form-urlencoded;字符集=UTF-8 。从 spring 日志中我可以看到已解决 [org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported]。但如果可以从 url 参数检查内容类型,我想禁用标题检查广告。但是 ignoreAcceptHeader(true) 不起作用。
    【解决方案2】:

    我解决了在我的 Spring Boot 应用程序中添加以下转换器的问题:

    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;
        }
    

    通过站点管理器进行跨域请求是必需的

    【讨论】:

      猜你喜欢
      • 2017-05-20
      • 2017-06-21
      • 1970-01-01
      • 1970-01-01
      • 2013-01-13
      • 2013-08-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多