skip to Main Content

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

2

Answers


  1. Chosen as BEST ANSWER

    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


  2. 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 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

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search