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 :
-
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é surmyXml
doivent être traitées de la même manière que les demandes dont l'en-tête accept est réglé surapplication/xml
." Cependant, maintenant je suis presque sûr que Brian voulait dire, "Demandes se terminant par.myXml
ou avec le paramètre de requêteformat=myXml
doivent être traitées commeapplication/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
comoapplication/xml
? -
Brian déclare que ce qu'istibekesi devrait probablement faire est d'enregistrer une
HttpMessageConverter
puis l'enregistrer avecapplication/xml
ymyXml
. 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 quemyXml
) pour utiliser cetteHttpMessageConverter
. -
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 surtext/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.