Merentas domain ialah senario yang sering dihadapi dalam pembangunan, dan ia juga merupakan isu yang sering dibincangkan dalam temu bual. Menguasai penyelesaian merentas domain biasa dan prinsip di sebaliknya bukan sahaja boleh meningkatkan kecekapan pembangunan kami, tetapi juga menjadikan kami lebih selesa dalam temu duga.
Jadi hari ini saya akan bercakap dengan anda tentang beberapa cara biasa untuk menyelesaikan isu merentas domain dari perspektif bahagian hadapan.
Sebelum bercakap tentang merentas domain, mari kita lihat dahulu komponen URL:
URL Ia biasanya mengandungi protokol, nama hos, nombor port, laluan, parameter pertanyaan dan sauh .
Contoh URL ditunjukkan di sini:
https://www.example.com:8080/path/resource.html?page=1&sort=desc#header
Dalam contoh di atas:
● Protokolnya ialah HTTPS
● Nama hos ialah www.example.com
● Nombor port ialah 8080
● Laluan ialah /path/resource.html
● Parameter pertanyaan ialah page=1&sort=desc
● Titik anchor ialah pengepala
Yang dipanggil domain silang, Ini bermakna mana-mana bahagian protokol, nama hos dan nombor port dalam URL permintaan adalah berbeza.
Mengambil URL di atas sebagai contoh, kaedah penulisan berikut dianggap sebagai domain silang dengannya:
http://www.example.com:8080/ // 协议不同 https://www.example.a.com:8080/ // 主机名不同 https://www.example.com:8081/ // 端口号不同
Malahkejadian masalah merentas domain dihadkan oleh dasar asal penyemak imbas yang sama.
所谓同源策略,其实是浏览器的一种安全机制,用于限制一个网页中的网络请求仅能够访问来自同一源(域名、协议和端口号均相同)的资源,主要目的是防止恶意网站通过脚本窃取其他网站的敏感数据,保障用户的隐私和安全。
Apabila skrip sebelah penyemak imbas (fail js) mengakses sumber rangkaian dalam domain lain, masalah merentas domain akan berlaku.
Seperti yang dinyatakan sebelum ini, berlakunya masalah merentas domain dihadkan oleh dasar asal penyemak imbas yang sama, jadi ada adalah cara biasa untuk menyelesaikan masalah merentas domain Penyelesaiannya sebenarnya berkisar pada penyemak imbas:
Dalam pembangunan biasa kami, adalah paling banyak. biasa digunakan untuk menyelesaikan masalah merentas domain Penyelesaiannya adalah dengan menggunakan pelayan proksi .
Pelayan proksi menyelesaikan masalah merentas domain dengan benar-benar merebut ciri bahawa dasar asal yang sama hanya terhad kepada penyemak imbas yang mengakses pelayan dan tiada sekatan ke atas pelayan mengakses pelayan berfungsi sebagai perantara Pelayan mempunyai fungsi pemajuan permintaan .
Khususnya, halaman web yang ditulis oleh jurutera bahagian hadapan berjalan pada pelayan proksi yang dibina dengan perancah seperti webpack Apabila halaman web bahagian hadapan memulakan permintaan rangkaian dalam penyemak imbas, permintaan itu sebenarnya dihantar kepada pelayan proksi , maka pelayan proksi akan memajukan permintaan kepada pelayan sasaran, dan kemudian memajukan respons yang dikembalikan oleh pelayan sasaran kepada klien.
Pelayan proksi memainkan peranan geganti dalam proses ini dan boleh mengubah suai, menapis serta memintas permintaan dan respons untuk mencapai beberapa fungsi tertentu. Oleh kerana halaman web bahagian hadapan berjalan pada pelayan proksi, tiada masalah merentas domain.
Jadi, bagaimanakah pelayan proksi menghantar permintaan dalam persekitaran dalam talian dan persekitaran pembangunan?
Dalam persekitaran dalam talian, kami biasanya menggunakan nginx sebagai proksi terbalik untuk memajukan permintaan bahagian hadapan yang dimajukan kepada antara muka sasaran.
nginx ialah pelayan web konkurensi tinggi yang ringan, dipacu acara, merentas platform dan boleh dikonfigurasikan pada kedua-dua tetingkap dan Linux.
Cara utama ia berfungsi sebagai pelayan proksi untuk menyelesaikan masalah merentas domain dalam pembangunan ialah mendengar port yang sedang dijalankan bagi URL bahagian hadapan dalam talian, dan kemudian memajukan permintaan apabila ia menemui a permintaan yang mengandungi tag khas .
Dalam persekitaran pembangunan, sama ada ia adalah projek hadapan yang dibina dengan bantuan webpack atau menggunakan vite atau perancah lain, teras menyelesaikan masalah merentas domain Dilaksanakan dengan bantuan http-proxy-middleware middleware. Teras http-proxy-middleware middleware ialah enkapsulasi lanjut http-proxy.
Di sini kami mula-mula menunjukkan kod sampel untuk menggunakan http-proxy-middleware dalam projek untuk melaksanakan fungsi pemajuan permintaan:
const { createProxyMiddleware } = require('http-proxy-middleware'); module.exports = { server: { proxy: { // 将 /api/* 的请求代理到 http://localhost:3000/* '/api': { target: 'http://localhost:3000', changeOrigin: true, pathRewrite: { '^/api': '/' } } } } };
Kemudian kami boleh melakukannya sendiri Gunakan nod asli dan gunakan perpustakaan proksi http untuk membina pelayan proksi Demo dengan fungsi pemajuan permintaan Rakan yang berminat boleh menguji dan bermain sendiri :
1.<🎜. > Mula-mula anda perlu Cipta folder kosong (dinamakan dalam bahasa Inggeris) sebagai folder projek, dan kemudian gunakan perintah npm init -y untuk menaik taraf projek kepada projek nod:
npm init -y
2. Kemudian buat fail index.html dalam direktori akar projek untuk memulakan permintaan merentas domain:
<!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. Kemudian buat fail dalam direktori akar projek Cipta fail index.js baharu untuk menulis kod sebelah pelayan.
Fail index.js ialah fail teras untuk melaksanakan pelayan proksi dengan fungsi pemajuan permintaan.
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. Kemudian tulis kandungan pelayan sasaran fail target.js untuk menguji akses merentas domain:
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的原理是通过动态创建