web-dev-qa-db-fra.com

Spring MVC 4: le type de contenu "application/json" n'est pas défini correctement

J'ai un contrôleur mappé avec l'annotation suivante:

@RequestMapping(value = "/json", method = RequestMethod.GET, produces = "application/json")
@ResponseBody
public String bar() {
    return "{\"test\": \"jsonResponseExample\"}";
}

Je retourne une chaîne JSON valide, cependant, le type de contenu lorsque je visualise la réponse dans Chrome Dev Tools dans le navigateur n'est pas application/json, mais simplement text/html. Pourquoi le type de contenu n'est-il pas défini?

Mon web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app metadata-complete="true" version="3.0"
    xmlns="http://Java.Sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://Java.Sun.com/xml/ns/javaee http://Java.Sun.com/xml/ns/javaee/web-app_3_0.xsd">

    <display-name>Spring MVC Web Application</display-name>

    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <!-- static assets -->
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.js</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.css</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/dispatcher-servlet.xml</param-value>
    </context-param>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
</web-app>

Mon dispatcher-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="
    http://www.springframework.org/schema/beans     
    http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
    http://www.springframework.org/schema/context 
    http://www.springframework.org/schema/context/spring-context-4.1.xsd">


    <context:annotation-config />

    <context:component-scan base-package="com.mydomain.controllers" />

    <bean id="viewResolver"
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/" />
        <property name="suffix" value=".jsp" />
    </bean>
</beans>

Utilisation de WildFly 8.1 comme serveur d'applications.

20
user1757703

La première chose à comprendre est que le RequestMapping#produces() élément de

@RequestMapping(value = "/json", method = RequestMethod.GET, produces = "application/json")

sert uniquement à restreindre le mappage pour vos gestionnaires de demandes. Cela ne fait rien d'autre.

Ensuite, étant donné que votre méthode a un type de retour de String et est annotée de @ResponseBody, la valeur de retour sera gérée par StringHttpMessageConverter qui définit l'en-tête Content-type sur text/plain. Si vous souhaitez renvoyer vous-même une chaîne JSON et définir l'en-tête sur application/json, utilisez un type de retour de ResponseEntity (supprimez @ResponseBody) et ajoutez-lui les en-têtes appropriés.

@RequestMapping(value = "/json", method = RequestMethod.GET, produces = "application/json")
public ResponseEntity<String> bar() {
    final HttpHeaders httpHeaders= new HttpHeaders();
    httpHeaders.setContentType(MediaType.APPLICATION_JSON);
    return new ResponseEntity<String>("{\"test\": \"jsonResponseExample\"}", httpHeaders, HttpStatus.OK);
}

Notez que vous devriez probablement avoir

<mvc:annotation-driven /> 

dans la configuration de contexte de votre servlet pour configurer votre configuration MVC avec les valeurs par défaut les plus appropriées.

55

Utilisez la bibliothèque jackson et l'annotation @ResponseBody sur le type de retour pour le contrôleur.

Cela fonctionne si vous souhaitez retourner des POJO représentés par JSon. Si vous souhaitez retourner String et non les POJO en tant que JSon, veuillez vous reporter à la réponse Sotirious.

3
John

Comme d'autres personnes l'ont commenté, le type de résultat de votre méthode étant String, Spring n'aura pas besoin de faire quoi que ce soit avec le résultat.

Si vous modifiez votre signature de sorte que le type de retour soit quelque chose qui nécessite une mise en forme, cela devrait aider:

@RequestMapping(value = "/json", method = RequestMethod.GET, produces = "application/json")
@ResponseBody
public Map<String, Object> bar() {
    HashMap<String, Object> map = new HashMap<String, Object>();
    map.put("test", "jsonRestExample");
    return map;
}
2
ninj

Pas exactement pour cet OP, mais pour ceux qui ont rencontré 404 et ne peuvent pas définir la réponse content-type à "application/json" (aucun content-type). Une possibilité est qu'un serveur réponde en réalité 406 mais Explorer (par exemple, chrome) l’imprime en tant que 404. 

Si vous ne personnalisez pas le convertisseur de message, spring utilisera AbstractMessageConverterMethodProcessor.Java. Il courrait:

List<MediaType> requestedMediaTypes = getAcceptableMediaTypes(request);
List<MediaType> producibleMediaTypes = getProducibleMediaTypes(request, valueType, declaredType);

et s’ils n’ont aucun chevauchement (le même élément), il lancera HttpMediaTypeNotAcceptableException et cela aboutira finalement à 406. Peu importe s’il s’agisse d’un ajax, d’un GET/POST ou d’une action de forme, si la demande uri se termine par un .html n'importe quel suffixe, la requestedMediaTypes serait "text/[ce suffixe]", et ceci est en conflit avec producibleMediaTypes, qui est habituellement:

"application/json"  
"application/xml"   
"text/xml"          
"application/*+xml" 
"application/json"  
"application/*+json"
"application/json"  
"application/*+json"
"application/xml"   
"text/xml"          
"application/*+xml"
"application/xml"  
"text/xml"         
"application/*+xml"
0
Tiina