크로스 도메인은 개발 과정에서 자주 접하는 시나리오이자, 인터뷰에서도 자주 거론되는 질문이기도 합니다. 공통 도메인 간 솔루션과 그 뒤에 숨은 원칙을 익히면 개발 효율성이 향상될 뿐만 아니라 인터뷰에 더욱 편안해집니다.
그래서 오늘은 프런트엔드 관점에서 도메인 간 문제를 해결하는 몇 가지 일반적인 방법에 대해 이야기해 보겠습니다.
교차 도메인에 대해 이야기하기 전에 먼저 URL 구성을 살펴보겠습니다.
URL 구성에는 일반적으로 프로토콜, 호스트 이름, 포트 번호, 경로가 포함됩니다. , 쿼리 매개변수 및 앵커 여러 부분.
URL의 예는 다음과 같습니다.
https://www.example.com:8080/path/resource.html?page=1&sort=desc#header
위의 예에서:
● 프로토콜은 HTTPS입니다.
● 호스트 이름은 www.example.com
● 포트 번호는 8080입니다.
● 경로는 /path입니다. /resource.html
● 쿼리 매개변수는 page=1&sort=desc
● 앵커는 header
소위 크로스 도메인은 요청 URL의 프로토콜, 호스트 이름 및 포트 번호의 일부가 다른.
위 URL을 예로 들면 다음과 같은 작성 방식은 크로스 도메인으로 간주됩니다.
http://www.example.com:8080/ // 协议不同 https://www.example.a.com:8080/ // 主机名不同 https://www.example.com:8081/ // 端口号不同
실제로크로스 도메인 문제 발생은 제한적입니다. 브라우저의 동일 출처 정책에 따라.
所谓同源策略,其实是浏览器的一种安全机制,用于限制一个网页中的网络请求仅能够访问来自同一源(域名、协议和端口号均相同)的资源,主要目的是防止恶意网站通过脚本窃取其他网站的敏感数据,保障用户的隐私和安全。
브라우저 측 스크립트(js 파일)가 다른 도메인의 네트워크 리소스에 액세스하면 도메인 간 문제가 발생합니다.
앞서 언급했듯이 크로스 도메인 문제의 발생은 브라우저의 동일 출처 정책에 의해 제한되므로 크로스 도메인 문제를 해결하는 일반적인 솔루션은 실제로 브라우저를 중심으로 이루어집니다. :
우리의 일반적인 개발에서 도메인 간 문제를 해결하기 위해 가장 일반적으로 사용되는 솔루션은 프록시 서버를 사용하는 것입니다.
프록시 서버 크로스 도메인 문제를 해결하기 위해 동일 출처 정책이 브라우저의 서버 액세스에 의해서만 제한되고 서버의 서버 액세스에는 제한이 없다는 기능을 실제로 캡처합니다. 중간 서버로서 요청 전달 기능이 있습니다.
구체적으로 프런트엔드 엔지니어가 작성한 웹페이지는 webpack과 같은 스캐폴딩으로 구축된 프록시 서버에서 실행됩니다. 프런트엔드 웹페이지가 브라우저에서 네트워크 요청을 시작하면 해당 요청이 실제로 프록시 서버로 전송됩니다. , 프록시 서버 요청은 대상 서버로 전달되고 대상 서버에서 반환된 응답은 클라이언트로 전달됩니다. 프록시 서버는 이 프로세스에서 중계 역할을 하며 일부 특정 기능을 달성하기 위해 요청과 응답을 수정, 필터링 및 가로챌 수 있습니다.프런트엔드 웹페이지는 프록시 서버에서 실행되기 때문에 크로스도메인 문제가 없습니다.
그렇다면 프록시 서버는 온라인 환경과 개발 환경에서 어떻게 요청을 전달할까요?nginx를 역방향 프록시로 사용하여 프런트엔드 요청을 대상 인터페이스로 전달합니다.
nginx는 경량의 동시성 웹 서버, 이벤트 중심, 크로스 플랫폼이며 Windows와 Linux 모두에서 구성할 수 있습니다.개발 중 도메인 간 문제를 해결하기 위해 프록시 서버로 사용하는 주요 방법은 온라인 프런트 엔드 URL의 실행 중인 포트를 수신한 다음 특수 태그가 포함된 요청을 만난 후 요청을 전달하는 것입니다.
의 도움으로 달성됩니다. http-proxy-middleware 미들웨어 . http-proxy-middleware 미들웨어의 핵심은 http-proxy를 추가로 캡슐화한 것입니다.
다음은http-proxy-middleware를 사용하여 프로젝트에서 요청 전달 기능을 구현하는 샘플 코드입니다.
const { createProxyMiddleware } = require('http-proxy-middleware'); module.exports = { server: { proxy: { // 将 /api/* 的请求代理到 http://localhost:3000/* '/api': { target: 'http://localhost:3000', changeOrigin: true, pathRewrite: { '^/api': '/' } } } } };그런 다음
우리는 기본 노드를 직접 사용하고 http-proxy 라이브러리를 사용하여 요청 전달을 구축할 수 있습니다. 기능 프록시 서버 데모, 관심 있는 친구가 직접 테스트하고 플레이할 수 있습니다. :
1. 먼저 프로젝트 폴더로 빈 폴더(영어 이름)를 만든 다음 npm init -y를 사용해야 합니다. 프로젝트를 설치하는 명령 프로젝트는 노드로 업그레이드되었습니다:
npm init -y
2. 그런 다음 프로젝트 루트 디렉터리에 index.html 파일을 만들어 교차 도메인 요청을 시작합니다.
<!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. 그런 다음 새 를 만듭니다. 서버측 코드를 작성하기 위한 프로젝트 루트 디렉터리 .js 파일의 인덱스입니다.
index.js 파일은 요청 전달 기능을 갖춘 프록시 서버를 구현하기 위한 핵심 파일입니다.
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. 그런 다음 도메인 간 액세스 테스트를 위해 대상 서버 target.js 파일의 내용을 작성합니다.
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的原理是通过动态创建3f1c4e4b6b16bbbd69b2ee476dc4f83a标签,向服务器发送请求并在请求URL中传递一个回调函数名(通常是在本地定义的函数名),服务器在返回的数据中将这个回调函数名和实际数据一起封装成一个JavaScript函数的调用,返回给客户端,客户端利用该回调函数对数据进行处理。
JSONP之所以能够跨域请求数据,是因为浏览器对于3f1c4e4b6b16bbbd69b2ee476dc4f83a标签的请求不会受到同源策略的限制。
需要注意的是,使用JSONP技术的前提是服务器需要支持JSONP的方式,即在返回的数据中包含回调函数名和实际数据的封装,否则客户端无法处理返回的数据。
此外,JSONP只支持GET请求,不支持POST等其他HTTP请求方式,因为3f1c4e4b6b16bbbd69b2ee476dc4f83a标签只支持GET请求。
因此JSONP这种方式在我们的开发中使用的场景不多。
CORS全称为Cross-Origin Resource Sharing,它通过HTTP头部信息告诉浏览器哪些跨域请求是被允许的,从而实现安全的跨域访问。
CORS解决跨域需要浏览器端和服务器端的配合。原理是在服务器端设置HTTP头部信息,告诉浏览器允许哪些源(域名、协议、端口)访问服务器上的资源,如果请求的源不在允许的列表中,则浏览器将拒绝访
问。
服务器可以通过设置Access-Control-Allow-Origin、Access-Control-Allow-Headers、Access-Control-Allow-Methods等HTTP头部信息来控制跨域访问权限。
具体地,当浏览器发起跨域请求时,会先发送一个OPTIONS请求(预检请求),询问服务器是否允许该跨域请求。
服务器接收到该请求后,根据请求中的HTTP头部信息判断是否允许该请求。
如果允许,则返回相应的HTTP头部信息告知浏览器可以继续发送真正的跨域请求。如果不允许,则返回一个错误状态码,告诉浏览器该请求被拒绝。
预检请求时,请求头常见参数有:
请求头 | 值 |
---|---|
Origin | 表示请求的源地址,即发起跨域请求的域名 |
Access-Control-Request-Method | 表示实际请求采用的HTTP方法 |
Access-Control-Request-Headers | 表示实际请求中所携带的额外请求头信息,比如自定义请求头等 |
预检请求时,响应头常见参数有:
响应头 | 值 |
---|---|
Access-Control-Allow-Origin | *、origin... |
Access-Control-Allow-Headers | POST, GET, PUT, DELETE, OPTIONS |
Access-Control-Allow-Methods | Content-Type, Authorization.. |
Access-Control-Allow-Credentials | true |
Access-Control-Max-Age | 86400 |
CORS를 사용하기 위한 전제 조건은 서버가 관련 HTTP 헤더 정보를 설정해야 하며 브라우저가 CORS를 지원한다는 것입니다. 또한 CORS는 최신 브라우저만 지원하며 일부 이전 브라우저는 CORS를 지원하지 않을 수 있습니다.
postMessage 등과 같은 기타 솔루션 .
최근에는 프론트엔드와 백엔드 기술의 급속한 발전으로 독립 프론트엔드와 백엔드 개발은 점차 주류 개발 모델이 되었습니다. 프런트엔드와 백엔드 프로그래머는 인터페이스에 동의한 다음 해당 모듈을 독립적으로 개발하고 마지막으로 인터페이스의 공동 디버깅을 수행하면 됩니다. 인터페이스 공동 디버깅 프로세스 중에 개발 환경의 크로스 도메인 개발은 해결해야 할 문제입니다.
또한 현재 백엔드 프로젝트를 패키징하여 클라우드로 옮긴 후 프런트엔드 페이지가 온라인 주소를 통해 백엔드 인터페이스에 액세스할 때 온라인 환경의 크로스 도메인도 문제가 됩니다. 그건 해결해야 해.
이 문서에서는 몇 가지 일반적인 교차 도메인 솔루션에 대해 설명합니다. 각 솔루션에는 실제 상황에 따라 해당 도메인 간 문제를 해결하는 데 적합한 솔루션을 선택할 수 있습니다.
추천 튜토리얼: nginx 튜토리얼
위 내용은 도메인 간 문제를 해결하는 방법은 무엇입니까? 일반적인 솔루션에 대한 간략한 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!