J'essaie de faire une demande d'origine croisée en utilisant RestTemplate de Spring. La communication se fait entre deux applications Web Spring-boot, toutes deux exécutées sur localhost mais sur un port différent. Ce que je fais c'est:

HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setOrigin("http://localhost:8083");
httpHeaders.add("Authorization", token);

HttpEntity<Void> httpEntity = new HttpEntity<>(httpHeaders);

ParameterizedTypeReference<List<MyObj>> beanType = new ParameterizedTypeReference<List<MyObj>>() {};
ResponseEntity<List<MyObj>> list = restTemplate.exchange(serviceURL, HttpMethod.GET, httpEntity, beanType);

L'appel est exécuté, l'en-tête "Authorization" est passé très bien, mais peu importe ce que j'essaye, il n'y a pas d'en-tête "Origin" du côté récepteur. Lorsque je crée une requête similaire à l'aide d'un autre outil (SoapUI, plugin RestClient Chrome, etc.), l'en-tête est passé tel que je le fournis.

Pour imprimer tous les en-têtes côté réception, j'utilise une implémentation de javax.servlet.Filter avec:

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
        throws IOException, ServletException {
    HttpServletRequest request = (HttpServletRequest) req;
    HttpServletResponse response = (HttpServletResponse) res;
    Enumeration<String> headerNames = request.getHeaderNames();
    while (headerNames.hasMoreElements()) {
        String headerName = headerNames.nextElement();
        log.info(headerName + ": " + request.getHeader(headerName));
    }
}

Pourquoi l'en-tête d'origine n'est-il pas passé lors de l'utilisation de RestTemplate?

10
Krzysztof Ś 17 janv. 2017 à 17:24

2 réponses

Meilleure réponse

J'ai eu le même problème que j'ai passé un siècle à résoudre.

La cause première est cette ligne de la documentation RestTemplate

Remarque: par défaut, le RestTemplate s'appuie sur les fonctionnalités JDK standard pour établir des connexions HTTP.

Si vous vérifiez le code source de la classe HttpUrlConnection en Java, vous trouverez ci-dessous le bloc de code, et l'en-tête Origin est l'un des en-têtes restreints qui interdisent les modifications:

/*
 * Restrict setting of request headers through the public api
 * consistent with JavaScript XMLHttpRequest2 with a few
 * exceptions. Disallowed headers are silently ignored for
 * backwards compatibility reasons rather than throwing a
 * SecurityException. For example, some applets set the
 * Host header since old JREs did not implement HTTP 1.1.
 * Additionally, any header starting with Sec- is
 * disallowed.
 *
 * The following headers are allowed for historical reasons:
 *
 * Accept-Charset, Accept-Encoding, Cookie, Cookie2, Date,
 * Referer, TE, User-Agent, headers beginning with Proxy-.
 *
 * The following headers are allowed in a limited form:
 *
 * Connection: close
 *
 * See http://www.w3.org/TR/XMLHttpRequest2.
 */
 private static final boolean allowRestrictedHeaders;
 private static final Set<String> restrictedHeaderSet;
 private static final String[] restrictedHeaders = {
    /* Restricted by XMLHttpRequest2 */
    //"Accept-Charset",
    //"Accept-Encoding",
    "Access-Control-Request-Headers",
    "Access-Control-Request-Method",
    "Connection", /* close is allowed */
    "Content-Length",
    //"Cookie",
    //"Cookie2",
    "Content-Transfer-Encoding",
    //"Date",
    //"Expect",
    "Host",
    "Keep-Alive",
    "Origin",
    // "Referer",
    // "TE",
    "Trailer",
    "Transfer-Encoding",
    "Upgrade",
    //"User-Agent",
    "Via"
};

Il existe une solution simple à ce problème, il suffit de définir un argument JVM

-Dsun.net.http.allowRestrictedHeaders=true 

Ou ajoutez une ligne dans votre code

System.setProperty("sun.net.http.allowRestrictedHeaders", "true");

Qui supprime la restriction.

21
Cady 25 janv. 2017 à 00:54

J'ai eu le même problème. J'ai découvert que le client http apache n'a pas ce problème et envoie une requête avec 'Origin': http: // hc.apache.org/

HttpOptions httpOptions = new 
HttpOptions(url)
httpOptions.setHeader("Origin", "test")
httpOptions.setHeader("Content-Type", "application/json")
BasicHttpClientConnectionManager manager = new 
BasicHttpClientConnectionManager()
HttpClient client = new MinimalHttpClient(manager)
client.execute(httpOptions)
1
HuTa 20 avril 2017 à 12:14