Le cross-domain est un scénario souvent rencontré en développement, et c'est aussi une question souvent évoquée en entretien. La maîtrise des solutions inter-domaines communes et des principes qui les sous-tendent peut non seulement améliorer notre efficacité de développement, mais également nous rendre plus à l'aise lors des entretiens.
Alors, parlons aujourd'hui de plusieurs façons courantes de résoudre les problèmes inter-domaines du point de vue du front-end.
Avant de parler de cross-domain, jetons d'abord un coup d'œil à la composition d'une URL :
La composition d'une URL comprend généralement le protocole, le nom d'hôte, le numéro de port, le chemin , paramètres de requête et ancres Plusieurs parties.
Un exemple d'URL est présenté ici :
https://www.example.com:8080/path/resource.html?page=1&sort=desc#header
Dans l'exemple ci-dessus :
gird Le protocole est HTTPS
g Le nom d'hôte est www.example.com
g Le numéro de port est 8080
g Le chemin est /path /resource.html
● Le paramètre de requête est page=1&sort=desc
Quantity L'ancre est header
Ce qu'on appelle le cross-domain signifie que toute partie du protocole, du nom d'hôte et du numéro de port dans l'URL de la requête est différent.
En prenant l'URL ci-dessus comme exemple, les méthodes d'écriture suivantes sont considérées comme étant inter-domaines :
http://www.example.com:8080/ // 协议不同 https://www.example.a.com:8080/ // 主机名不同 https://www.example.com:8081/ // 端口号不同
En faitl'apparition de problèmes inter-domaines est limitée par la politique de même origine du navigateur.
所谓同源策略,其实是浏览器的一种安全机制,用于限制一个网页中的网络请求仅能够访问来自同一源(域名、协议和端口号均相同)的资源,主要目的是防止恶意网站通过脚本窃取其他网站的敏感数据,保障用户的隐私和安全。
Lorsque des scripts côté navigateur (fichiers js) accèdent aux ressources réseau d'autres domaines, des problèmes inter-domaines se produiront.
Comme mentionné précédemment, l'apparition de problèmes inter-domaines est limitée par la politique de même origine du navigateur, de sorte que les solutions courantes pour résoudre les problèmes inter-domaines tournent en fait autour des navigateurs. :
Dans notre développement habituel, la solution la plus couramment utilisée pour résoudre les problèmes inter-domaines est d'utiliser un serveur proxy.
Serveur proxyPour résoudre le problème inter-domaines, il capture en fait la fonctionnalité selon laquelle la politique de même origine n'est limitée que par l'accès du navigateur au serveur, et il n'y a aucune restriction sur l'accès du serveur au serveur . En tant que serveur intermédiaire, il dispose d'une fonction de transfert de requêtes.
Plus précisément, la page Web écrite par l'ingénieur front-end s'exécute sur un serveur proxy construit par un échafaudage tel que webpack. Lorsque la page Web frontale initie une requête réseau dans le navigateur, la requête est en fait envoyée au serveur proxy. , puis le serveur proxy La demande sera transmise au serveur cible, puis la réponse renvoyée par le serveur cible sera transmise au client.
Le serveur proxy joue un rôle de relais dans ce processus et peut modifier, filtrer et intercepter les requêtes et réponses pour réaliser certaines fonctions spécifiques. Étant donné que la page Web frontale s'exécute sur le serveur proxy, il n'y a pas de problème entre domaines.
Alors, comment le serveur proxy transmet-il les requêtes dans l'environnement en ligne et l'environnement de développement ?
Dans l'environnement en ligne, nous utilisons généralement nginx comme proxy inverse pour transmettre la requête frontale à l'interface cible.
nginx est un serveur Web léger à haute concurrence, piloté par événements, multiplateforme et peut être configuré à la fois sur Windows et Linux.
La principale méthode qu'il utilise en tant que serveur proxy pour résoudre les problèmes inter-domaines en cours de développement consiste à écouter le port en cours d'exécution de l'URL frontale en ligne, puis à transmettre la requête après avoir rencontré une requête contenant une balise spéciale.
Dans l'environnement de développement, qu'il s'agisse d'un projet front-end construit à l'aide de webpack ou de vite ou d'un autre échafaudage, l'essentiel de la résolution des problèmes inter-domaines est réalisé avec l'aide de http-proxy-middleware middleware . Le cœur du middleware http-proxy-middleware est une autre encapsulation de http-proxy.
Voici un exemple de code qui utilise http-proxy-middleware pour implémenter la fonction de transfert de requêtes dans le projet :
const { createProxyMiddleware } = require('http-proxy-middleware'); module.exports = { server: { proxy: { // 将 /api/* 的请求代理到 http://localhost:3000/* '/api': { target: 'http://localhost:3000', changeOrigin: true, pathRewrite: { '^/api': '/' } } } } };
Ensuitenous pouvons utiliser le nœud natif nous-mêmes et utiliser la bibliothèque http-proxy pour créer un transfert de requête fonction Démo du serveur proxy, les amis intéressés peuvent tester et jouer par eux-mêmes :
1. Tout d'abord, vous devez créer un dossier vide (nommé en anglais) comme dossier du projet, puis utiliser le npm init -y commande pour installer le projet Projet mis à niveau vers le nœud :
npm init -y
2. Créez ensuite un fichier index.html dans le répertoire racine du projet pour lancer des requêtes inter-domaines :
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>请求转发测试</title> </head> <body> <h1>请求转发测试</h1> <p id="message"></p> <script> fetch('/api/login') .then(response => response.text()) .then(data => { document.getElementById('message').textContent = data; }); </script> </body> </html>
3. Créez ensuite un nouveau index dans le répertoire racine du projet fichier .js pour écrire du code côté serveur.
Le fichier index.js est le fichier principal pour implémenter un serveur proxy avec fonction de transfert de requêtes.
const http = require('http'); const httpProxy = require('http-proxy'); const fs = require('fs'); const path = require('path'); // 创建代理服务器实例 const proxy = httpProxy.createProxyServer({}); // 创建HTTP服务器 const server = http.createServer((req, res) => { if (req.url === '/' || req.url.endsWith('.html')) { // 读取HTML文件 const filename = path.join(__dirname, 'index.html'); fs.readFile(filename, 'utf8', (err, data) => { if (err) { res.writeHead(500); res.end('Error reading HTML file'); } else { res.writeHead(200, { 'Content-Type': 'text/html' }); res.end(data); } }); } else if (req.url.startsWith('/api')) { // 重写路径,替换跨域关键词 req.url = req.url.replace(/^\/api/, ''); // 将请求转发至目标服务器 proxy.web(req, res, { target: 'http://localhost:3000/', changeOrigin: true, }); } }); // 监听端口 server.listen(8080, () => { console.log('Server started on port 8080'); });
4. Ensuite, écrivez le contenu du fichiertarget.js du serveur cible pour tester l'accès inter-domaines :
const http = require('http'); const server = http.createServer((req, res) => { if (req.url.startsWith('/login')) { res.writeHead(200, { 'Content-Type': 'text/plain' }); res.end('我是localhost主机3000端口下的方法,恭喜你访问成功!'); } else { res.writeHead(200, { 'Content-Type': 'text/plain' }); res.end('Hello, world!'); } }); server.listen(3000, () => { console.log('Target server is listening on port:3000'); })
5. 打开终端,输入启动目标服务器的命令:
node ./target.js //项目根目录下执行
6. 再开一个终端启动代理服务器,等待浏览器端发起请求就可以啦:
node ./index.js //项目根目录下执行
7. 最后在浏览器里访问http://localhost:8080, 打开控制台即可查看效果:
可以发现,浏览器network模块的网络请求确实是访问的8080端口的方法,但是我们的服务器默默的做了请求转发的功能,并将请求转发获取到的内容返回到了前端页面上。
其实http-proxy是对node内置库http的进一步封装,网络请求的核心部分还是使用http创建一个服务器对象去访问的。感兴趣的同学可以再读读http-proxy的源码~
除了代理服务器这种绕过浏览器同源策略的解决方式外,从前端的角度解决跨域问题还有如下一些常见的方法:
JSONP的原理是通过动态创建