Cross-domain is a scenario often encountered in development, and it is also a question often discussed in interviews. Mastering common cross-domain solutions and the principles behind them can not only improve our development efficiency, but also make us more comfortable in interviews.
SoLet’s talk to you today about several common ways to solve cross-domain problems from a front-end perspective.
Before talking about cross-domain, let’s first take a look at the components of a URL:
The contents of a URL Composition, usually contains protocol, host name, port number, path, query parameters and anchor parts.
An example of a URL is shown here:
https://www.example.com:8080/path/resource.html?page=1&sort=desc#header
In the above example:
● The protocol is HTTPS
● The hostname is www.example.com
● The port The number is 8080
● The path is /path/resource.html
● The query parameter is page=1&sort=desc
● The anchor point is header
The so-called cross-domain refers to It means that any part of the protocol, host name, and port number in the request URL is different.
Taking the above URL as an example, the following writing methods are considered to be cross-domain with it:
http://www.example.com:8080/ // 协议不同 https://www.example.a.com:8080/ // 主机名不同 https://www.example.com:8081/ // 端口号不同
In fact The occurrence of cross-domain problems is limited by the browser's same-origin policy.
The so-called same-origin policy is actually a security mechanism of the browser, which is used to restrict network requests in a web page to only access files from the same source (the domain name, protocol and port number are the same) resources, the main purpose is to prevent malicious websites from stealing sensitive data from other websites through scripts, and to protect user privacy and security.
When the browser-side script (js file) accesses network resources in other domains, cross-domain problems will occur.
As mentioned earlier, the occurrence of cross-domain problems is limited by the browser’s same-origin policy, so common solutions to cross-domain problems The solution actually revolves around the browser:
In our usual development, is most commonly used to solve cross-domain problems The solution is to use a proxy server.
Proxy serverTo solve the cross-domain problem, we actually grasp the feature that the same-origin policy is only limited to the browser accessing the server, and there is no restriction on the server accessing the server. As an intermediate The server has a request forwarding function.
Specifically, the web page written by the front-end engineer runs on a proxy server built by scaffolding such as webpack. When the front-end web page initiates a network request in the browser, the request is actually sent to the proxy server. , then the proxy server will forward the request to the target server, and then forward the response returned by the target server to the client.
The proxy server plays a relay role in this process and can modify, filter and intercept requests and responses to achieve some specific functions. Because the front-end web page runs on the proxy server, there is no cross-domain problem.
So how does the proxy server forward requests in the online environment and development environment?
In the online environment, we generally use nginx as a reverse proxy to forward the front-end requests forwarded to the target interface.
nginx is a lightweight high-concurrency web server, event-driven, cross-platform, and can be configured on both window and Linux.
The main way it serves as a proxy server to solve cross-domain problems in development is to listen to the running port of the online front-end URL, and then forward the request after encountering a request containing a special tag .
In the development environment, whether it is a front-end project built with the help of webpack or using vite or other scaffolding, the core of solving cross-domain problems is Implemented with the help of http-proxy-middleware middleware. The core of http-proxy-middleware middleware is a further encapsulation of http-proxy.
Here is a sample code that uses http-proxy-middleware to implement the request forwarding function in the project:
const { createProxyMiddleware } = require('http-proxy-middleware'); module.exports = { server: { proxy: { // 将 /api/* 的请求代理到 http://localhost:3000/* '/api': { target: 'http://localhost:3000', changeOrigin: true, pathRewrite: { '^/api': '/' } } } } };
Then we can use native node, use the http-proxy library to build a proxy server Demo with request forwarding function. Interested friends can test and play by themselves:
1. First you need to create a Use the empty folder (named in English) as the project folder, and then use the npm init -y command to upgrade the project to a node project:
npm init -y
2. Next Create an index.html file in the project root directory to initiate cross-domain requests:
<!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. Then create a new index in the project root directory .js file to write server-side code.
The index.js file is the core file for implementing a proxy server with request forwarding function.
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. Then write the contents of the target servertarget.js file for testing cross-domain access:
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的原理是通过动态创建