2 votes

Comment puis-je enregistrer un HttpMessageConverter personnalisé pour traiter un Content-Type invalide dans Spring ?

J'écris du code pour POST à une API tierce en utilisant une RestTemplate . Cette API répond avec le content-type text;charset=UTF-8 et Spring lance un InvalidMediaTypeException car ce type de contenu ne contient pas de / . Est-il possible d'indiquer à Spring qu'un type de contenu de type text doit être traité de la même manière qu'un type de contenu de type text/plain ? Si oui, comment puis-je y parvenir ?

C'est le code qui cause le problème. Je ne peux pas afficher le URL mais je suppose que cela n'a pas vraiment d'importance.

// Make the body of the request.
MultiValueMap<String, String> body = new LinkedMultiValueMap<String, String>();
body.add("Customer Street", "a test street!");

// Make the headers of the request.
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
headers.setAccept(Arrays.asList(MediaType.TEXT_PLAIN));

// Create an HTTP entity.
HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<MultiValueMap<String, String>>(body, headers);

// Get a rest template
RestTemplate rest = new RestTemplate();

// Post the data.
String resp = null;
try {
    resp = rest.postForObject(URL, entity, String.class);
} catch (InvalidMediaTypeException e) {
    e.printStackTrace();
    return;
}

Questions relatives à l'OS

Ce site Cette question décrit presque exactement le problème que je rencontre. La réponse acceptée à cette question est, essentiellement, "Voir cette autre question", ce que j'ai fait ; elle est décrite ci-dessous.

Sur ce (liée à la réponse à la question ci-dessus), istibekesi demande l'utilisation d'un type de contenu personnalisé de myXml et fournit un exemple de configuration qui n'a pas fonctionné. Brian Clozel's La réponse m'a aidé à comprendre certaines choses sur les types de contenu que je ne comprenais pas auparavant, mais je suis toujours confus sur ces points :

  1. Brian dit que la configuration donnée doit enregistrer myXml en tant qu'extension du chemin d'accès / paramètre pour la négociation à application/xml . J'ai d'abord cru comprendre que Brian voulait dire : "Les requêtes dont l'en-tête accept est réglé sur myXml doivent être traitées de la même manière que les demandes dont l'en-tête accept est réglé sur application/xml ." Cependant, maintenant je suis presque sûr que Brian voulait dire, "Demandes se terminant par .myXml ou avec le paramètre de requête format=myXml doivent être traitées comme application/xml ." Ma deuxième interprétation est-elle correcte ? Si oui, pourquoi n'a pas la configuration donnée force Spring à traiter les requêtes dont l'en-tête accept est fixé à myXml como application/xml ?

  2. Brian déclare que ce qu'istibekesi devrait probablement faire est d'enregistrer une HttpMessageConverter puis l'enregistrer avec application/xml y myXml . Je pense que je comprends ce que Brian veut dire par "enregistrer un". HttpMessageConverter Cependant, je n'arrive pas à trouver comment enregistrer un type de média personnalisé (tel que myXml ) pour utiliser cette HttpMessageConverter .

  3. Malheureusement, le conseil de Brian "utiliser un type de média comme application/vnd.foobar.v.1.0+xml "n'est pas utile pour moi, car je n'ai aucun contrôle sur le type de contenu de la réponse qui m'est envoyée. J'ai essayé de définir les en-têtes acceptés de ma requête sur text/plain mais ça n'a pas changé la réponse.

Autres recherches

La trace de la pile de l'exception lancée par Spring est la suivante

org.springframework.http.InvalidMediaTypeException: Invalid mime type "text;charset=UTF-8": does not contain '/'
    at org.springframework.http.MediaType.parseMediaType(MediaType.java:452)
    at org.springframework.http.HttpHeaders.getContentType(HttpHeaders.java:745)
    at org.springframework.web.client.HttpMessageConverterExtractor.getContentType(HttpMessageConverterExtractor.java:114)
    at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:85)
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:655)
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:613)
    at org.springframework.web.client.RestTemplate.postForObject(RestTemplate.java:380)
    at com.agileBTS.hellosignTest.App.main(App.java:47)
Caused by: org.springframework.util.InvalidMimeTypeException: Invalid mime type "text;charset=UTF-8": does not contain '/'
    at org.springframework.util.MimeTypeUtils.parseMimeType(MimeTypeUtils.java:256)
    at org.springframework.http.MediaType.parseMediaType(MediaType.java:449)

J'ai parcouru le code source de chaque fonction sur la trace de la pile pour voir si je pouvais comprendre ce qui se passait, et je peux voir clairement que la fonction parseMimeType (la première méthode qui lève une exception) est assez simple : si le mime-type ne contient pas d'icône / il jette une exception. Je ne comprends pas comment un code va contourner cela, à moins de sous-classer MimeTypeUtils et forcer Spring à utiliser ma sous-classe. Est-ce que c'est ce qu'il faut faire ? Cela semble très difficile.

Mises à jour

1

Dans leur réponse, Sean Carroll a suggéré que j'enregistre le "text" type mime en utilisant la ligne

c.setSupportedMediaTypes(Arrays.asList(MediaType.TEXT_PLAIN, MediaType.parseMediaType("text")));

Cependant, si vous consultez le code source de l'application #parseMediaType méthode aquí à la ligne 487, vous verrez que #parseMediaType confie la majeure partie du travail à la MimeTypeUtils#parseMimeType méthode. En regardant que code source aquí à partir de la ligne 176, il est clair que le #parseMimeType lancera un IllegalMimeTypeException à la ligne 193, car "text" ne contient pas de / (en fait, il s'agit de la ligne de code exacte qui déclenche l'erreur d'utilisation de la fonction IllegalMimeTypeException dans mon application). J'ai besoin d'un moyen de contourner ce problème.

2

Après avoir effectué des tests, j'ai déterminé que la configuration d'un gestionnaire de négociation de contenu ne fonctionne pas non plus dans mon cas. D'après ce Je pense qu'il est clair que la configuration XML :

<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
    <property name="mediaTypes">
        <map>
            <entry key="json" value="application/json" />
            <entry key="xml" value="application/xml" />
       </map>
    </property>
</bean>

est équivalent à cette configuration Java :

@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.mediaType("xml", MediaType.APPLICATION_XML)
        .mediaType("json", MediaType.APPLICATION_JSON);
}

En regardant le ContentNegotiationConfigurer#mediaType documentation des méthodes aquí J'ai vu la ligne "Ajouter un mappage à partir d'une clé", extrait d'une extension de chemin ou d'un paramètre de requête ..." (c'est moi qui souligne) ; je suppose que l'exclusion de "accepter les en-têtes" de cette citation était intentionnelle.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X