Ce que cet article vous apporte est une solution très détaillée et complète aux problèmes inter-domaines (avec des exemples). Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer.
Problèmes inter-domaines courants
Brève description
En tant que débutant front-end, je ne connais que JSONP et CORS en cross -domaine. Je ne l'ai pas compris en profondeur. Mais à mesure que le recrutement printanier approche, même les recrues doivent battre des ailes. J'ai soigneusement étudié les problèmes inter-domaines ces derniers jours et j'ai écrit cet article, dans l'espoir d'être utile aux développeurs. Avant de lire cet article, j'espère que vous avez quelques connaissances sur les points suivants.
Politique de même origine du navigateur
nodejs
iframe
docker, nginx
Pourquoi devrions-nous étudier les problèmes inter-domaines
Parce que la politique de même origine du navigateur stipule que les clients d'un certain domaine ne peuvent pas lire ou écrire des ressources dans un autre domaine sans autorisation explicite. Dans le développement réel, le front-end et le back-end sont souvent séparés l'un de l'autre, et les déploiements de projets front-end et back-end ne se font souvent pas au sein d'un serveur ou sous différents ports d'un serveur. Si le front-end souhaite obtenir les données du back-end, il doit lancer une requête. Si elle est traitée correctement, elle sera limitée par la politique de même origine du navigateur. Le backend peut recevoir la demande et renvoyer les données, mais le frontend ne peut pas recevoir les données.
Plusieurs méthodes inter-domaines
L'inter-domaine peut être grossièrement divisé en deux objectifs
Lorsque le front-end et le back-end sont séparés , le front-end utilise le Cross-domain
Cross-domain pour la communication des pages front-end dans différents domaines
Cross-domain pour la séparation front-end et back-end
Partage de ressources inter-origines (CORS))
CORS est une solution de partage de ressources inter-domaines afin de résoudre les problèmes inter-domaines, en ajoutant une série d'en-têtes de requête et de réponses. en-têtes, la transmission des données entre sites est standardisée et sécurisée
Les en-têtes de requêtes incluent principalement
En-tête de requête | Explication | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
|
L'en-tête Origin indique le nom de domaine source de la requête cross-domaine dans une requête cross-domaine ou une pré-demande. | ||||||||||
Access-Control-Request-Method | L'en-tête Access-Control-Request-Method est utilisé pour indiquer l'utilisation de requêtes inter-domaines La méthode HTTP réelle | ||||||||||
Access-Control-Request-Headers
|
Access-Control-Request-Headers est utilisée lors d'une demande préalable, informer le serveur des informations d'en-tête de requête qui seront contenues dans la requête inter-domaines à lancer |
En-tête de réponse | Explication th> |
---|---|
Access-Control-Allow-Origin | L'en-tête Access-Control-Allow-Origin porte le Le nom de domaine de demande inter-domaines autorisé après vérification côté serveur peut être un nom de domaine spécifique ou un * (indiquant n'importe quel nom de domaine). |
Access-Control-Expose-Headers | L'en-tête Access-Control-Expose-Headers est utilisé pour permettre aux retours de se croiser -demandes de domaine Une liste d'en-têtes de réponse Seul le contenu des en-têtes de réponse de la liste est accessible au navigateur. |
Access-Control-Max-Age | Access-Control-Max-Age est utilisé pour indiquer au navigateur qu'il peut pré-vérification L'heure à laquelle le résultat de la requête est mis en cache. Pendant la période de validité du cache, le navigateur utilisera les résultats de la pré-vérification mis en cache pour déterminer s'il doit envoyer une requête inter-domaines. |
Access-Control-Allow-Methods | Access-Control-Allow-Methods est utilisé pour indiquer au navigateur qu'il peut envoyer réellement Lors des requêtes inter-domaines, les méthodes de requête prises en charge peuvent être une liste de méthodes spécifiques ou un * (indiquant n'importe quelle méthode). |
Le client n'a qu'à définir l'en-tête de la requête en fonction de la spécification.
Le serveur reconnaît et renvoie l'en-tête de réponse correspondant selon la spécification, ou installe le plug-in correspondant, modifie le fichier de configuration du framework correspondant, etc. Cela dépend du langage et du framework utilisés par le serveur
Exemple de configuration SpringBoot CORS
Un morceau de code sur la configuration CORS dans un Spring Boot project
HttpServletResponse httpServletResponse = (HttpServletResponse) response; String temp = request.getHeader("Origin"); httpServletResponse.setHeader("Access-Control-Allow-Origin", temp); // 允许的访问方法 httpServletResponse.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE, PATCH"); // Access-Control-Max-Age 用于 CORS 相关配置的缓存 httpServletResponse.setHeader("Access-Control-Max-Age", "3600"); httpServletResponse.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept,token"); httpServletResponse.setHeader("Access-Control-Allow-Credentials", "true");
JSONP Cross-domain
Le principe de jsonp est d'utiliser la balise <script> Créez donc dynamiquement une balise <srcipt>, src est l'interface de destination + obtenir le paquet de données + le nom de la fonction pour le traitement des données. Après avoir reçu la requête GET, l'arrière-plan analyse et renvoie le nom de la fonction (données) au front-end. La balise <script> du front-end exécute dynamiquement la fonction de traitement <br/>Observez le code suivant </script>
Front. -end code
nbsp;html> <meta> <title>Title</title> <script> var script = document.createElement('script'); script.type = 'text/javascript'; // 传参并指定回调执行函数为getData script.src = 'http://localhost:8080/users?username=xbc&callback=handleData'; document.body.appendChild(script); // 回调执行函数 function handleData(res) { data = JSON.stringify(res) console.log(data); } </script>
Code backend (nodejs)
var querystring = require('querystring'); var http = require('http'); var server = http.createServer(); server.on('request', function(req, res) { var params = querystring.parse(req.url.split('?')[1]); var fn = params.callback; // jsonp返回设置 res.writeHead(200, { 'Content-Type': 'text/javascript' }); var data = { user: 'xbc', password: '123456' } res.write(fn + '(' + JSON.stringify(data) + ')'); res.end(); }); server.listen('8080'); console.log('Server is running at port 8080...');
Dans cet exemple, la résolution reçue par le frontend est comme ceci
La page d'accueil ressemble à ceci
Remarque
JSONP utilise
Le proxy inverse nginx réalise des idées inter-domaines
Idées
Étant donné que le navigateur a des restrictions de politique de même origine, nous mettons le projet front-end Ne suffit-il pas de mettre l'adresse de l'interface api demandée par le front-end sous la même source ? Combinés au proxy inverse fourni par le serveur Web, les problèmes inter-domaines peuvent être résolus sans aucune configuration sur le front-end ou le back-end.
La véritable adresse d'arrière-plan du backend : http://xxx.xxx.xxx.xxx:8085
L'adresse d'arrière-plan du projet Spring Boot déployé à l'aide de Tomcat s'appelle gsms_test
Adresse du serveur nginx : http://xxx.xxx.xxx.xxx:8082
Tomcat et nginx sont tous deux configurés avec Docker et la redirection de port est effectuée
Conditions d'utilisation : L'environnement de développement est un système Linux
nginx /etc/nginx/conf.d/default.conf
Le code de configuration est le suivant
server { listen 80; server_name localhost; #charset koi8-r; #access_log /var/log/nginx/host.access.log main; location / { # root /usr/share/nginx/html/dist; # 前端项目路径 # index index.html index.htm; proxy_pass http://localhost:8001/; # 前端本机地址,实现自动更新 autoindex on; autoindex_exact_size on; autoindex_localtime on; } location /gsms_test/ { proxy_pass 后端真实地址; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } # proxy the PHP scripts to Apache listening on 127.0.0.1:80 # #location ~ \.php$ { # proxy_pass http://127.0.0.1; #} # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 # #location ~ \.php$ { # root html; # fastcgi_pass 127.0.0.1:9000; # fastcgi_index index.php; # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; # include fastcgi_params; #} # deny access to .htaccess files, if Apache's document root # concurs with nginx's one # #location ~ /\.ht { # deny all; #} }
Les pages de différents domaines communiquent entre domaines
window.name + iframe cross-domain
window.name Ce sont les données partagées par une fenêtre dans le navigateur. Elles existent toujours après chargement sur différentes pages (ou même différents noms de domaine) (la valeur ne changera pas si elle n'est pas modifiée). ), et peut supporter très longtemps valeur du nom (2 Mo). Par exemple Si une page du domaine a souhaite obtenir des données d'une page du domaine b, vous pouvez modifier la valeur window.name dans le domaine b. Basculez le domaine a vers le domaine b et revenez en arrière pour obtenir la valeur window.name du domaine b. Mais nous ne voulons certainement pas changer de page pendant le développement, nous devons donc le combiner avec iframe.
Exemple (implémenté avec thinkjs)
a Le code de domaine est le suivant
nbsp;html> <meta> <title>A 域</title> <h1>server A</h1> <script> function getData() { var iframe = document.getElementById('proxy'); iframe.onload = function () { var name = iframe.contentWindow.name; // 获取iframe窗口里的window.name值 console.log(name) } // 由于iframe信息传递也受同源策略限制,所以在window.name被B域修改后,将iframe转回A域下。以便获取iframe的window.name值 iframe.src = 'http://127.0.0.1:8360/sub.html' } </script> <iframe> </iframe>
b Le code de domaine
nbsp;html> <meta> <title>New ThinkJS Application</title> <h1>server 2</h1> <script> window.name = 'user: xbc'; </script>
En raison de la restriction de la politique de même origine, la page parent obtient des informations incomplètes à partir de la page iframe inter-domaines, elle doit donc être convertie en domaine A. après que le window.name de l'iframe soit modifié par le domaine B. N'importe quelle page (window.name ne doit pas être modifiée de ce côté) est obtenue.
Étant donné que l'accès mutuel entre iframe et la page parent est également restreint par la politique de même origine, une page proxy est requise pour obtenir un accès inter-domaines accéder.
Personnellement, je pense que c'est un peu gênant. Si vous êtes intéressé, veuillez voir comment le front-end utilise une page proxy. pour résoudre le problème de l'accès inter-domaines iframe ?
Résumé
Les méthodes ci-dessus sont toutes des méthodes inter-domaines que j'ai utilisées ou testées. Il existe également des méthodes inter-domaines telles que postMessage et WebSocket, qui n'ont jamais été utilisés auparavant. Contacter sans explication. Divers problèmes doivent être pris en compte spécifiquement lors de l'utilisation de ces méthodes dans un projet
情况 | 方法 |
---|---|
只有GET请求 | JSONP |
对兼容性及浏览器版本无要求 | CORS |
对兼容性及浏览器版本有要求 | iframe 或 服务器反向代理(linux 环境下开发) |
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!