クロスドメインは開発においてよく遭遇するシナリオであり、インタビューでもよく議論される質問でもあります。一般的なクロスドメイン ソリューションとその背後にある原則を習得すると、開発効率が向上するだけでなく、面接もより快適になります。
それでは今日は、フロントエンドの観点からクロスドメインの問題を解決するためのいくつかの一般的な方法についてお話しましょう。
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/ // 端口号不同
なぜクロスドメインなのか
いわゆる同一オリジン ポリシーは、実際にはブラウザのセキュリティ メカニズムであり、Web ページ内のネットワーク リクエストを制限して、同じソース (ドメイン名、プロトコルとポート番号は同じです)リソースの主な目的は、悪意のある Web サイトがスクリプトを通じて他の Web サイトから機密データを盗むのを防ぎ、ユーザーのプライバシーとセキュリティを保護することです。
ブラウザ側のスクリプト (js ファイル) が他のドメインのネットワーク リソースにアクセスすると、クロスドメインの問題が発生します。
クロスドメインの問題を解決する方法
1. プロキシ サーバー
プロキシサーバー
クロスドメイン問題を解決するために、同一オリジンポリシーはサーバーにアクセスするブラウザのみに限定されており、サーバーにアクセスするブラウザには制限がないという特徴を実際に把握しています。サーバーにアクセスするサーバー仲介としてサーバーはリクエスト転送機能を持っています。 具体的には、フロントエンドエンジニアが書いたWebページは、webpackなどのスキャフォールディングで構築されたプロキシサーバー上で動作し、フロントエンドWebページがブラウザ上でネットワークリクエストを開始すると、実際にリクエストが送信されます。プロキシ サーバーに送信すると、プロキシ サーバーはリクエストをターゲット サーバーに転送し、ターゲット サーバーから返された応答をクライアントに転送します。
プロキシ サーバーは、このプロセスで中継の役割を果たし、リクエストと応答を変更、フィルタリング、インターセプトして、特定の機能を実現します。フロントエンド Web ページはプロキシ サーバー上で実行されるため、クロスドメインの問題は発生しません。
それでは、プロキシ サーバーはオンライン環境や開発環境でどのようにリクエストを転送するのでしょうか?
1. オンライン環境
nginx は軽量で同時実行性の高い Web サーバーであり、イベント駆動型のクロスプラットフォームであり、ウィンドウと Linux の両方で構成できます。
開発中のクロスドメインの問題を解決するプロキシ サーバーとして機能する主な方法は、オンライン フロントエンド URL の実行ポートをリッスンし、リクエストが発生した後にリクエストを転送することです。特別なタグ
が含まれています。2. 開発環境
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 -y2 にアップグレードします。 次に、プロジェクトのルート ディレクトリに
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 をサポートしていない可能性があります。
WebSocket、postMessage など
インターフェイスの共同デバッグ プロセス中に、開発環境でのクロスドメイン開発は解決する必要がある問題です。
さらに、現在のバックエンド プロジェクトがパッケージ化されてクラウドに移動された後、フロントエンド ページがオンライン アドレスを介してバックエンド インターフェイスにアクセスするとき、クロスドメインオンライン環境における問題も解決すべき問題です。
この記事では、いくつかの一般的なクロスドメイン ソリューションについて説明します。これらのソリューションにはそれぞれ、独自の長所と短所があります。実際の状況に応じて適切なソリューションを選択して、対応するクロスドメインの問題を解決できます~ 推奨チュートリアル:以上がクロスドメインの問題を解決するにはどうすればよいですか?一般的なソリューションの簡単な分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。