記事ディレクトリ
1. クロスドメインとは
ドメイン名アドレスがhttp://www.a.com:8080/scripts/jquery.jsの場合
、その構成は次のとおりです。
- プロトコル: http://
- サブドメイン: www
- サブドメイン: a.com
- ポート番号: 8080
- リクエスト リソース アドレス: scripts/jquery.js
クロス ドメインの根本的な原因は同源策略
、. いわゆる同じオリジンとは、同じドメイン名、プロトコル、およびポートを指します. ページがスクリプトを実行すると、アクセスされたリソースが同じオリジンであるかどうかがチェックされます. そうでない場合、ブラウザはコンソールに例外を報告します.データを要求するとき、アクセスの拒否を促します。注意:跨域限制访问,其实是浏览器的限制。理解这一点很重要!!!
クロスドメイン アクセスの例:
リクエストはクロスドメインなので、リクエストは送信されましたか?
跨域并不是请求发不出去,请求能发出去,服务端能收到请求并正常返回结果,只是结果被浏览器拦截了
. クロスドメイン リクエストをフォームから開始できるのに、なぜ Ajax ではできないのか疑問に思うかもしれません.最終的な分析では、クロスドメインは、ユーザーが別のドメイン名でコンテンツを読み取れないようにするためです.Ajax は応答を取得できます.ブラウザはこれを安全ではないため、応答が傍受されます。ただし、フォームは新しいコンテンツを取得しないため、クロスドメイン リクエストを開始できます。同時に、クロスドメインはCSRFを完全に防ぐことはできないことも示しています。
2. クロスドメインへのいくつかのソリューション
次の図に示すように、インターネット上でクロスドメインを解決するには多くの方法があります。
次に、クロスドメインの一般的な解決策をいくつか紹介します. 知りたい人は、インターネットで調べることができます.
2.1、クロスドメインを解決する JSONP の方法
Jsonp には、コールバック関数とデータの 2 つの部分が含まれています。
コールバック関数は、応答が来たときに現在のページで呼び出される関数です。
データは、コールバック関数のパラメーターであるコールバック関数に渡される json データです。
function handleResponse(response){
console.log('The responsed data is: '+response.data);
}
var script = document.createElement('script');
script.src = 'http://www.baidu.com/json/?callback=handleResponse';
document.body.insertBefore(script, document.body.firstChild);
/*handleResonse({"data": "zhe"})*/
//原理如下:
//当我们通过script标签请求时
//后台就会根据相应的参数(json,handleResponse)
//来生成相应的json数据(handleResponse({"data": "zhe"}))
//最后这个返回的json数据(代码)就会被放在当前js文件中被执行
//至此跨域通信完成
短所:
1) セキュリティの問題 (リクエスト コードにセキュリティ リスクがある可能性があります)
2) jsonp リクエストが失敗したかどうかを判断するのは簡単ではありません
2.2、クロスドメインを解決する CORS の方法 (一般的で、通常はサーバーを変更するだけで済みます)
CORS 全称是"跨域资源共享"(Cross-origin resource sharing)
. CORS はブラウザとサーバーで同時にサポートする必要がありますが、現在は基本的にすべてのブラウザがサポートしているため、サーバー側のサーバーが CORS インターフェースを実装していることを確認するだけで、ドメイン間で通信できるようになります。
実装方法: Access-Control-Allow-Origin フィールドがデータ パケットのヘッダーに設定された後、データ パケットがブラウザに送信された後、ブラウザはここで設定されたホワイトリストに従って「手放し」、Web ページを許可します。 ajax を使用したクロスドメイン アクセスへのホワイトリストのサーバーに対応します。
CORS は、サーバー側の応答にヘッダー情報を追加することで、クロスドメインの問題を解決します。
Access-Control-Allow-Origin 允许请求的域
Access-Control-Allow-Methods 允许请求的方法
Access-Control-Allow-Headers 预检请求后,告知发送请求需要有的头部
Access-Control-Allow-Credentials 表示是否允许发送cookie,默认false;
Access-Control-Max-Age 本次预检的有效期,单位:秒;
Java 言語を例にとると、サーバー側のフィルター設定は次のようになります。
// 接收客户端发送的 origin (重要)
// res.setHeader("Access-Control-Allow-Origin", "*") // * 代表允许所有的地址跨域访问
// 如果是白名单,可以定义跨域访问白名单
// String[] authOrigin = {'http://127.0.0.1:5500'}
// if(authOrigin.includes(origin)) {
// // 只有白名单中的地址才可以跨域访问
// res.setHeader('Access-Control-Allow-Origin', origin)
// }
res.setHeader("Access-Control-Allow-Origin", origin)
//服务器支持的所有跨域请求的方法
res.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE,UPDATE")
//允许跨域设置可以返回其他子段,可以自定义字段
res.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Length, X-CSRF-Token, Token,session")
// 允许浏览器(客户端)可以解析的头部 (重要)
res.setHeader("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers")
//设置缓存时间
res.setHeader("Access-Control-Max-Age", "172800")
//允许客户端传递校验信息比如 cookie (重要)
res.setHeader("Access-Control-Allow-Credentials", "true")
その他参考:CORS公式サイト
2.3. クロスドメインを解決する Nginx リバース プロキシ (推奨、シンプルな構成)
原則: クロスドメインはブラウザーによって制限されるため、サーバー要求サーバーはブラウザーの同一生成元ポリシーによって制限されません。
2.4、WebSocket がクロスドメインを解決
WebSocket は、単一の永続的な接続を介して全二重の双方向通信を提供することを目標とするブラウザー API です。(同一生成元ポリシーは WebSocket には適用されません)
原則: JS が WebSocket を作成した後、接続を開始するために HTTP 要求がブラウザーに送信されます。サーバーからの応答を取得した後、確立された接続は、HTTP アップグレードを使用して HTTP プロトコルから WebSocket プロトコルに切り替えられます。
var socket = new WebSockt('ws://www.baidu.com');//http->ws; https->wss
socket.send('hello WebSockt');
socket.onmessage = function(event){
var data = event.data;
}
欠点:
WebSocket プロトコルをサポートするサーバーでのみ適切に動作します。
2.5、クロスドメインを解決する PostMessage メソッド (HTML5 の XMLHttpRequest レベル 2 の API)
- http://a.com/index.html のコード:
<iframe id="ifr" src="b.com/index.html"></iframe>
<script type="text/javascript">
window.onload = function() {
var ifr = document.getElementById('ifr');
var targetOrigin = 'http://b.com'; // 若写成'http://b.com/c/proxy.html'效果一样
// 若写成'http://c.com'就不会执行postMessage了
ifr.contentWindow.postMessage('I was there!', targetOrigin);
};
</script>
- http://b.com/index.html からのコード:
<script type="text/javascript">
window.addEventListener('message', function(event){
// 通过origin属性判断消息来源地址
if (event.origin == 'http://a.com') {
alert(event.data); // 弹出"I was there!"
alert(event.source); // 对a.com、index.html中window对象的引用
// 但由于同源策略,这里event.source不可以访问window对象
}
}, false);
</script>