Une demande normale
Récemment, d'autres doivent appeler une fonction de notre système, et l'autre partie espère fournir une API afin qu'elle puisse mettre à jour les données. Étant donné que ce camarade de classe est un développeur client, il a un code similaire à ce qui suit.
@RequestMapping (méthode = requestMethod.post, value = "/update.json", produmes = mediaType.Application_Json_Value) public @ResponseBody Contacter Update (@Requestbody Contistater Contacterro) {Logger.Debug ("GET UPDATE DEPTER {}", Contacterro.Tostring ()); == 123) {contacterro.sesername ("adminupdate-wangdachui");} return contacterro;}Le client initie une demande HTTP via le code pour l'appeler. Ensuite, l'élève a demandé: il espérait utiliser des appels JS via le navigateur, donc il y avait un problème de domaine croisé.
Pourquoi le domaine croisé
Autrement dit, le navigateur limite l'accès au code JS sous le site A pour faire une demande Ajax à l'URL sous le site B. Si le nom de domaine actuel est www.abc.com, le code JS exécuté dans l'environnement actuel ne peut pas accéder aux ressources sous le nom de domaine www.zzz.com pour des raisons de sécurité.
Par exemple: le code suivant peut être utilisé pour appeler l'interface normalement via le code JS sous ce nom de domaine
(fonction () {var url = "http: // localhost: 8080 / api / home / update.json"; var data = {"userId": 123, "username": "wangdachui"}; $. 'application / json'}). Done (function (result) {console.log ("succès"); console.log (result);}). fail (function () {console.log ("error");})}) () ()La sortie est:
Objet {userId: 123, nom d'utilisateur: "adminupdate-wangdachui"}Cependant, l'accès sous d'autres noms de domaine entraînera une erreur:
Options http: // localhost: 8080 / api / home / update.jsonxmlhttprequest ne peut pas charger http: // localhost: 8080 / api / home / update.json. La réponse à la demande FanDlight ne passe pas la vérification du contrôle d'accès: aucun en-tête «Access-Control-Allow-Origin» n'est présent sur la ressource demandée. L'origine «nul» n'est donc pas autorisée à accéder. La réponse avait le code d'état HTTP 403.
Solution
Jsonp
L'utilisation de JSONP pour croiser dans le domaine est une manière relativement courante, mais lorsque l'interface a été écrite, le serveur et le côté de l'appel doivent être transformés et compatibles avec l'interface d'origine, ce qui est un peu trop de travail, nous considérons donc d'autres méthodes.
Protocole CORS
Selon les références: chaque page doit retourner un en-tête HTTP nommé «Access-Control-Allow-Origin» pour permettre l'accès au site dans le domaine étranger. Vous pouvez simplement exposer des ressources limitées et un accès limité à l'extérieur du domaine. En mode COR, la responsabilité du contrôle d'accès peut être placée entre les mains du développeur de pages, pas l'administrateur du serveur. Bien sûr, les développeurs de pages doivent rédiger du code de traitement spécial pour permettre l'accès au monde extérieur. Nous pouvons le comprendre comme: Si une demande doit permettre un accès inter-domaine, vous devez définir l'origine accès à l'allow-allow dans l'en-tête HTTP pour décider quels sites permettre d'accéder. Si vous avez besoin d'autoriser les demandes de www.foo.com à cross-domain, vous pouvez définir: Access-Control-Allow-origin: http://www.foo.com. Ou Access-Control-Allow-Origin: *. CORS est pris en charge dans la plupart des navigateurs modernes dans le cadre de HTML5.
CORS a les en-têtes communs suivants
Access-Control-Allow-Origin: http: //foo.orgaccess-ctretrol-max-age: 3628800ACCESS-Control-Allow-Methods: Get, Put, DeleteAccess-Control-ALLOW-HEADERS: Content-Type "Access-Control-ALLOW-ORIGIN" " Demandes de domaine croisé. "Access-Control-MAX-Age" indique que dans les 3628800 secondes, aucune demande de pré-vérification n'est requise. Le résultat "Access-Control-Allow-Methods" indique qu'il permet à obtenir, mettre, supprimer les demandes hors domaine "Access-Control-Allow-Headers" indique qu'il permet
Processus de base CORS
Tout d'abord, une demande en avant-lumière est émise, qui émet d'abord une méthode d'options et une demande contenant l'en-tête "Origin" vers le serveur de ressources. Cette réponse peut contrôler la méthode de la demande COR, l'en-tête HTTP et les informations de vérification. Une véritable demande de domaine étranger ne sera lancée qu'après l'autorisation de la demande.
Spring MVC prend en charge les COR
La réponse à la demande FanDlight ne passe pas la vérification du contrôle d'accès: aucun en-tête «Access-Control-Allow-Origin» n'est présent sur la ressource demandée. L'origine «nul» n'est donc pas autorisée à accéder. La réponse avait le code d'état HTTP 403.
D'après le message d'erreur ci-dessus, nous pouvons voir que la raison directe est qu'il n'y a pas d'en-tête d'accès à l'origine à l'allow-allow dans l'en-tête de demande. Notre idée directe est donc d'ajouter cet en-tête à l'en-tête de demande. Le serveur peut retourner 403, indiquant que le serveur a effectivement traité la demande.
Intercepteur MVC
Tout d'abord, nous configurons un intercepteur pour intercepter la demande et enregistrer les informations d'en-tête de la demande.
Debug DeaireUrl: /api/home/update.json Méthode de débogage: Options Hôte de l'en-tête de débogage: LocalHost: 8080 Debug Header Connexion: Geef-Alive Debug Header Cache-Control: MAX-AGE = 0 Debug Header Access-Control-Request-Method Applewebkit / 537.36 (khtml, comme gecko) Chrome / 49.0.2623.87 Safari / 537.36 Header de debug Access-Control-Request-Headers: Accept, contenu-type Debat Accept-Language: ZH-CN, ZH; Q = 0,8, EN; Q = 0,6
L'impression du journal en aperçu a révélé que le statut de la réponse est 403 pour le moment. Le suivi des codes SpringMVC a révélé que dans org.springframework.web.servlet.dispatcherservlet.dodispatch, handlerexecutionchain sera obtenu en fonction de la demande. Après que SpringMVC ait acquis un processeur régulier, il vérifiera s'il s'agit d'une demande intermédiaire. Si c'est le cas, il remplacera l'instance d'origine.
@OverridePublic Final HandlereXecutionChain Gethandler (HttpServletRequest) lève une exception {objet Handler = GethandleRinternal (demande); if (handler == null) {handler = getDefaulthandler ();} if (handler == null) {retourne) handLername = (string) handler; handler = getApplicationContext (). getBean (handLername);} handlereXecutionChain ExecutionChain = GethandleReXecutionChain (gestionnaire, requête) this.corsConfigSource.getCorsConfiguration(request);CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);executionChain = getCorsHandlerExecutionChain(request, executionChain, config);} return ExecutionChain;}La méthode de vérification est également très simple, c'est-à-dire vérifier s'il existe un champ d'origine dans l'en-tête de demande.
public static boolean isCorsRequest (httpservletRequest request) {return (request.getheader (httpheaders.origin)! = null);}La demande sera ensuite remise à HttpRequestHandlerAdapter.Handle pour le traitement, et différentes logiques seront traitées en fonction de la poignée. Le jugement précédent est basé sur l'en-tête de la demande en tant que demande de domaine croisé. Le gestionnaire obtenu est préflightandler, qui est mis en œuvre comme suit:
@OverRidePublic void handlerequest (demande httpservletRequest, réponse httpservletResponse) lance ioException {corsprocessor.processRequest (this.config, demande, réponse);}Continuer à suivre
@OverridePublic Boolean ProcessRequest (CorsConfiguration Config, HttpServLetRequest Request, HttpServletResponse Response) lance ioException {if (! Corsutils.iscorsrequest (request)) {return true;} ServletserverHTTpResponse ServerResponse = new ServletserverHttpResponse (Response); ServletserverHttpRequest ServerRequest = new ServletserverHttpRequest (demande); if (webutils.issameorigin (serverRequest)) {logger.debug ("Skip Cors Traitement, la demande est un ONE-ORIGIN"); return true;} if (ResponseHascors (ServerResponse)) {logger.debug ("Skip Cors Process preflightRequest = corsutils.ispreflightReQuest (request); if (config == null) {if (preflightReSest) {RejectRequest (serverResponse); return false;} else {return true;}} return handleInternal (serverRequest, serverResponse, config, preflightReSest);}Cette méthode vérifie d'abord s'il s'agit d'une demande de domaine croisé, et si ce n'est pas le cas, il reviendra directement. Puis vérifie s'il est sous le même domaine, ou s'il a le champ d'origine accès à l'allow-allow dans l'en-tête de réponse ou s'il a l'accès-control-request-méthod dans la demande. Si la condition de jugement est remplie, la demande est rejetée.
À partir de cela, nous savons que le chèque peut être passé en définissant l'en-tête d'accès-contrôle-allow-original de la réponse avant le chèque. Nous gérons la pré-haine dans l'intercepteur. Ajouter le code suivant:
Response.sethEader ("Access-Control-Allow-Origin", "*");À l'heure actuelle, la demande d'options dans le navigateur renvoie 200. Mais toujours une erreur:
Le type de contenu du champ d'en-tête de demande n'est pas autorisé par l'accès-contrôle-allow-t-t-t-t-t-t-thers dans la réponse en avant-première.
Nous avons remarqué qu'il existe des capteurs d'accès-contrôle-request: accepter, type de contenu dans l'en-tête de demande, mais pas l'en-tête de demande. Pour le moment, le navigateur n'envoie pas la demande au besoin. Essayez de l'ajouter à la réponse:
Response.sethEader ("Access-Control-Allow-Headers", "Origin, X-Demande-With, Content-Type, Accept");Exécution réussie: Object {userId: 123, nom d'utilisateur: "adminupdate-wangdachui"}.
Jusqu'à présent: nous utilisons le principe d'analyse pour permettre à SpringMVC d'atteindre un domaine croisé, sans aucune modification de l'implémentation d'origine et du code client.
Springmvc 4
De plus, dans la référence 2, SpringMvc4 fournit une méthode très pratique pour implémenter un domaine croisé.
Utilisez des annotations dans la mise en évidence. @Crossorigin (origines = "http: // localhost: 9000")
Implémentation globale. Définition Héritage de classe WebmvcConfigurerAdapter
classe publique CorsConfigurerAdapter étend webmvcConfigurerAdapter {@OverRidePublic void addCorsMappings (CorsEgistry Registry) {registry.addmapping ("/ api / *"). ALLORIGHIGINS ("*");}}Injectez la classe dans le conteneur:
<fean> </bEAN>
Résumer
Ce qui précède est toutes les explications détaillées du code de demande de requête inter-domaine du printemps. J'espère que ce sera utile à tout le monde. Les amis intéressés peuvent continuer à se référer à d'autres sujets connexes sur ce site. S'il y a des lacunes, veuillez laisser un message pour le signaler. Merci vos amis pour votre soutien pour ce site!