简体   繁体   中英

Spring boot & Jquery 415 (Unsupported Media Type)

I trying to do an ajax cross domain post call to a spring rest web services api's in a secure context. From Jquery I can't set the contentType attribute cos then I have problem with the secure context. But without the contentType from spring I receive the following response: 415 (Unsupported Media Type)

Spring controller:

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

There is a way to disable on Spring the contentType check? All my data is json and I wish to set that as default avoiding the content-type header checking. I tryed defining a custom message converter and with the following code by did't work:

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

Thanks

You can specify content type your controller method accepts using the @RequestMapping annotation with the consumes field. For you use case you might consider accepting all content types with the following:

import org.springframework.http.MediaType;

@RequestMapping(value = "/all", method = RequestMethod.POST, consumes = {MediaType.ALL_VALUE})

UPDATE :

You should not disable the header checking, otherwise, the server does not know which content type is incoming and how to properly parse it.

Given your stack trace, I think the error is coming from a different source. You try to parse an incoming application/x-www-form-urlencoded; charset=UTF-8 application/x-www-form-urlencoded; charset=UTF-8 to a @RequestBody which is not possible with Spring.

This issue was already answered at a different place: Http Post request with content type application/x-www-form-urlencoded not working in Spring

I solved adding the following converter on my spring boot application:

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

In my Application:

@Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(customConverters());
    }

    public HttpMessageConverter customConverters() {
        HttpMessageConverter<Object> converter = new CustomMappingJackson2HttpMessageConverter(new ObjectMapper());
        return converter;
    }

Was necessary for cross domain request over siteminder

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM