J'essaie d'accéder à un service Web de données ouvertes qui me donne des informations sur le trafic. La documentation indique que les demandes doivent être GET
et doivent contenir Accept: application/json
Et Content-Type: application/json
. Je ne comprends pas pourquoi ils ont besoin du Content-Type
Mais ok:
J'ai essayé de récupérer des données avec juste l'en-tête Accept:
Mais j'obtiens toujours un 415 Unsupported Media Type
. Maintenant, je suis en train de l'essayer de cette façon (mais je ne sais pas si je configure vraiment les deux en-têtes correctement):
String entity = ClientBuilder.newClient().target(liveDataURI)
.path(liveDataPath)
.request(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.get(String.class);
Comme vous le voyez, j'utilise Jersey 2.2 et je reçois toujours un 415 Unsupported Media Type
.
MODIFIER
Je l'ai donc fait fonctionner mais je ne comprends pas pourquoi. accept(MediaType.APPLICATION_JSON)
et header("Content-type","application/json")
ne sont-ils pas les mêmes?
String responseEntity = ClientBuilder.newClient()
.target(liveDataURI)
.path(liveDataPath)
.request(MediaType.APPLICATION_JSON)
.header("Content-type", "application/json")
.get(String.class);
L'en-tête Accept
indique au serveur ce que votre client veut dans la réponse. L'en-tête Content-Type
Indique au serveur ce que le client envoie dans la demande. Donc, les deux sont pas les mêmes.
Si le serveur accepte uniquement application/json
, Vous devez envoyer une demande qui spécifie le contenu de la demande:
Content-Type: application/json
C'est pourquoi votre code édité fonctionne.
Modifier
Dans votre premier code, vous utilisez WebTarget.request(MediaType... acceptedResponseTypes)
. Les paramètres de cette méthode
définir les types de support de réponse acceptés.
Vous utilisez Innvocation.Builder.accept(MediaType... mediaTypes)
sur le résultat de cet appel de méthode. Mais accept()
n'ajoute aucun nouvel en-tête, c'est inutile dans votre premier code.
Vous ne spécifiez jamais le type de contenu de votre demande. Comme le serveur attend un en-tête Content-Type
, Il répond avec 415
.
accept(MediaType.APPLICATION_JSON)
etheader("Content-type","application/json")
ne sont-ils pas les mêmes?
Non, ils sont différents.
Voici comment ils sont liés:
Client Server
(header) (class/method annotation)
====================================================
Accept <---> @Produces
Content-Type <---> @Consumes
Le serveur consomme ce qu'il reçoit du client dans le corps (son format est spécifié dans Content-Type
) Et il produit ce que le client accepte (son format est spécifié dans Accept
).
Exemple:
Content-Type
= text/xml
(Il envoie un XML dans le corps)Accept
= application/json
(il s'attend à obtenir un JSON comme réponse)@Consumes(MediaType.TEXT_XML)
(il obtient un XML du client)@Produces(MediaType.APPLICATION_JSON)
(il envoie un JSON au client)Obs:
Le serveur peut être plus flexible, étant configuré pour obtenir/produire multiple possible formats.
Par exemple: un client peut envoyer un XML tandis qu'un autre client peut envoyer un JSON à la même méthode s'il a l'annotation suivante: @Consumes({ MediaType.APPLICATION_JSON, MediaType.TEXT_XML })
.
Les valeurs MediaType
ne sont que des constantes String
:
public final static String APPLICATION_JSON = "application/json";
public final static String TEXT_XML = "text/xml";
Vous pouvez utiliser le ContainerResponseFilter
pour définir l'en-tête Accept par défaut s'il n'est pas fourni dans la demande d'entrée.
@Provider
public class EntityResponseFilter implements ContainerResponseFilter {
private MediaType getExternalMediaType(){
MediaType mediaType = new MediaType("application", "vnd.xxx.resource+json")
return mediaType;
}
@Override
public void filter( ContainerRequestContext reqc , ContainerResponseContext resc ) throws IOException {
MediaType mediaType = getExternalMediaType();
List<MediaType> mediaTypes = reqc.getAcceptableMediaTypes();
if( mediaTypes.contains(mediaType) ) {
resc.setEntity( resc.getEntity(), new Annotation[0], mediaType );
}
// ...
}
}