Maison >interface Web >js tutoriel >Solution complète ultra-détaillée aux problèmes inter-domaines (avec exemples)

Solution complète ultra-détaillée aux problèmes inter-domaines (avec exemples)

不言
不言avant
2019-01-14 10:05:472604parcourir

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
请求头 解释
Origin Origin头在跨域请求或预先请求中,标明发起跨域请求的源域名。
Access-Control-Request-Method Access-Control-Request-Method头用于表明跨域请求使用的实际HTTP方法
Access-Control-Request-Headers Access-Control-Request-Headers用于在预先请求时,告知服务器要发起的跨域请求中会携带的请求头信息
Origin

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-Allow-Origin Access-Control-Allow-Origin头中携带了服务器端验证后的允许的跨域请求域名,可以是一个具体的域名或是一个*(表示任意域名)。
Access-Control-Expose-Headers Access-Control-Expose-Headers头用于允许返回给跨域请求的响应头列表,在列表中的响应头的内容,才可以被浏览器访问。
Access-Control-Max-Age Access-Control-Max-Age用于告知浏览器可以将预先检查请求返回结果缓存的时间,在缓存有效期内,浏览器会使用缓存的预先检查结果判断是否发送跨域请求。
Access-Control-Allow-Methods Access-Control-Allow-Methods用于告知浏览器可以在实际发送跨域请求时,可以支持的请求方法,可以是一个具体的方法列表或是一个*(表示任意方法)。
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
La réponse l'en-tête comprend principalement
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).

Comment utiliser

  • 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(&#39;script&#39;);
    script.type = &#39;text/javascript&#39;;

    // 传参并指定回调执行函数为getData
    script.src = &#39;http://localhost:8080/users?username=xbc&callback=handleData&#39;;
    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

Solution complète ultra-détaillée aux problèmes inter-domaines (avec exemples)

La page d'accueil ressemble à ceci

Solution complète ultra-détaillée aux problèmes inter-domaines (avec exemples)

Remarque

JSONP utilise , seules les requêtes GET peuvent alors être prises en charge. Les autres requêtes ne peuvent pas être mises en œuvre

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.

Prenons nginx comme exemple

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.confLe 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(&#39;proxy&#39;);
        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 = &#39;http://127.0.0.1:8360/sub.html&#39; 
    }
</script>
<iframe>        </iframe>

b Le code de domaine

nbsp;html>


<meta>
<title>New ThinkJS Application</title>


  <h1>server 2</h1>
<script>
  window.name = &#39;user: xbc&#39;;
</script>

Remarque

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.

Page proxy + iframe pour obtenir un accès inter-domaines

É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.

Solution complète ultra-détaillée aux problèmes inter-domaines (avec exemples)

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!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer