1.クロスドメインの問題が発生するのはなぜですか
ブラウザの同一生成元ポリシーの制限のため。同一生成元ポリシー(Sameoriginpolicy)は慣例であり、ブラウザーのコアで最も基本的なセキュリティ機能です。同一生成元ポリシーが欠落していると、ブラウザーの通常の機能が影響を受ける可能性があります。Webは同一生成元ポリシーに基づいて構築されており、ブラウザは同一生成元ポリシーの実装にすぎないと言えます。同一生成元ポリシーは、あるドメインのJavaScriptスクリプトが別のドメインのコンテンツと相互作用するのを防ぎます。いわゆる相同性(つまり、同じドメイン内)は、2つのページが同じプロトコル(プロトコル)、ホスト(ホスト)、およびポート番号(ポート)を持っていることを意味します
第二に、クロスドメインとは何ですか
リクエストURLのプロトコル、ドメイン名、ポートのいずれかが現在のページURLと異なる場合、それはクロスドメインです
現在のページのURL | リクエストされたページのURL | クロスドメインかどうか | 理由 |
http://www.test.com/ | http://www.test.com/index.html | 番号 | 同じソース(同じプロトコル、ドメイン名、およびポート番号) |
http://www.test.com/ | https://www.test.com/index.html | クロスドメイン | さまざまなプロトコル(http / https) |
http://www.test.com/ | http://www.baidu.com/ | クロスドメイン | メインドメイン名が異なります(test / baidu) |
http://www.test.com/ | http://blog.test.com/ | クロスドメイン | さまざまなサブドメイン(www / blog) |
http://www.test.com:8080/ | http://www.test.com:7001/ | クロスドメイン | ポート番号が異なります(8080/7001) |
3、非相同の制限は何ですか
[1]同一生成元ではないWebページのCookie、LocalStorage、およびIndexedDBを読み取ることができません
[2]同一生成元以外のWebページのDOMにアクセスできません
[3]同じ送信元アドレス以外にAJAXリクエストを送信できません
4つのクロスドメインソリューション
[1]同じ起源のウェブページからCookieを読み取れないという問題を解決するためにdocument.domainを設定します
JavaScript同一生成元ポリシーの制限により、スクリプトは、それらが属するドキュメントと同じソースを持つウィンドウとドキュメントのプロパティのみを読み取ることができます。
すでに成熟した製品システムを持っている企業の場合、異なるページが異なるサーバーに配置される可能性があります。これらのサーバーのドメイン名は異なりますが、上位レベルのドメイン名は同じです。
- たとえば、id.qq.com、www.qq.com、user.qzone.qq.comの場合、これらはすべてパブリックスーペリアドメイン名qq.comを持っています。これらのサーバー上のページ間のクロスドメインアクセスは、document.domainを介して実行できます。
同じdocument.domainのページは、同じドメイン名のサーバー上にあるのと同じです。プロトコルとポート番号も同じであれば、ドメイン間でデータにアクセスできます。
ケーススタディ
(1)同一生成元ページにアクセスします
- https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Cookieを開きます
- f12コンソールwindow.openページ https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers
- 次の図に示すように、返されたウィンドウオブジェクトのdocumentプロパティにアクセスして、正常にアクセスできることを確認します。
(2)アクセスプロトコルとポート番号が同じであり、ドメイン名に一貫性がありませんが、同じ上位レベルドメイン名のページ:
- id.qq.comを開き、f12コンソールを開き、window.openページ: www.qq.com、
- 返されたウィンドウオブジェクトのドキュメントプロパティへの同じアクセスで、アクセスが失敗したことがわかり、クロスドメインフォームへのアクセスがブロックされていることを確認します。
このとき、id.qq.comのdocument.domainとwww.qq.comのdocument.domainをそれぞれ印刷し、前者がid.qq.comで、後者がqq.comであることを確認します。
このとき、id.qq.comページのdocument.domainを手動で設定し、qq.comに設定して、www.qq.comのウィンドウオブジェクトのドキュメントに再度アクセスすると、アクセスが成功したことがわかります。
- 具体的な例の説明:document.domainを介したクロスドメインアクセス
[2]クロスドキュメント通信API:window.postMessage()
postMessageメソッドを呼び出して親ウィンドウhttp://test1.comを実装し、子ウィンドウhttp://test2.comにメッセージを送信します(子ウィンドウはこのメソッドを介して親ウィンドウにメッセージを送信することもできます)
次の問題を解決するために使用できます。
- ページと開いた新しいウィンドウ間のデータ転送
- 複数のウィンドウ間を通過するメッセージ
- ページとネストされたiframeメッセージング
- 上記の3つのシナリオでのクロスドメインデータ転送
// 父窗口打开一个子窗口
var openWindow = window.open('http://test2.com', 'title');
// 父窗口向子窗口发消息(第一个参数代表发送的内容,第二个参数代表接收消息窗口的url)
openWindow.postMessage('Nice to meet you!', 'http://test2.com');
メッセージイベントを呼び出して、相手から送信されたメッセージを監視します
// 监听 message 消息
window.addEventListener('message', function (e) {
console.log(e.source); // e.source 发送消息的窗口
console.log(e.origin); // e.origin 消息发向的网址
console.log(e.data); // e.data 发送的消息
},false);
【3】JSONP
JSONPは、サーバーとクライアント間のクロスオリジン通信の一般的な方法です。最大の機能は、シンプルなアプリケーションと優れた互換性(IEの下位バージョンとの互換性)ですが、欠点は、ポストリクエストではなく、取得リクエストのみをサポートすることです。
コアアイデア:Webページ<script>元素
はJSONデータをサーバーに追加して要求します。サーバーは要求を受信すると、指定された名前のコールバック関数のパラメーター位置にデータを送り返します。
①ネイティブ実現:
<script src="http://test.com/data.php?callback=dosomething"></script>
// 向服务器test.com发出请求,该请求的查询字符串有一个callback参数,用来指定回调函数的名字
// 处理服务器返回回调函数的数据
<script type="text/javascript">
function dosomething(res){
// 处理获得的数据
console.log(res.data)
}
</script>
②jQueryajax:
$.ajax({
url: 'http://www.test.com:8080/login',
type: 'get',
dataType: 'jsonp', // 请求方式为jsonp
jsonpCallback: "handleCallback", // 自定义回调函数名
data: {}
});
③Vue.js
this.$http.jsonp('http://www.domain2.com:8080/login', {
params: {},
jsonp: 'handleCallback'
}).then((res) => {
console.log(res);
})
【4】CORS
CORSは、クロスオリジンリソースシェアリングの略語です。これはW3C標準であり、クロスオリジンAJAXリクエストの基本的なソリューションです。
- 通常のクロスドメインリクエスト:サーバー側でAccess-Control-Allow-Originを設定するだけで済みます
- Cookieを使用したクロスドメインリクエスト:フロントエンドとバックエンドの両方を設定する必要があります
4.1 [フロントエンド設定] xhr.withCredentialsフィールドに従ってCookieがあるかどうかを確認します
①原生ajax
var xhr = new XMLHttpRequest(); // IE8/9需用window.XDomainRequest兼容
// 前端设置是否带cookie
xhr.withCredentials = true;
xhr.open('post', 'http://www.domain2.com:8080/login', true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send('user=admin');
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
alert(xhr.responseText);
}
};
②jQueryajax
$.ajax({
url: 'http://www.test.com:8080/login',
type: 'get',
data: {},
xhrFields: {
withCredentials: true // 前端设置是否带cookie
},
crossDomain: true, // 会让请求头中包含跨域的额外信息,但不会含cookie
});
③vue-resource
Vue.http.options.credentials = true
④axios
axios.defaults.withCredentials = true
4.2 [サーバー設定]
CORSのサーバー側サポートは、主にAccess-Control-Allow-Originを設定することによって実行されます。ブラウザが対応する設定を検出すると、Ajaxがクロスドメインアクセスを実行できるようになります。
①Javaの背景
/*
* 导入包:import javax.servlet.http.HttpServletResponse;
* 接口参数中定义:HttpServletResponse response
*/
// 允许跨域访问的域名:若有端口需写全(协议+域名+端口),若没有端口末尾不用加'/'
response.setHeader("Access-Control-Allow-Origin", "http://www.domain1.com");
// 允许前端带认证cookie:启用此项后,上面的域名不能为'*',必须指定具体的域名,否则浏览器会提示
response.setHeader("Access-Control-Allow-Credentials", "true");
// 提示OPTIONS预检时,后端需要设置的两个常用自定义头
response.setHeader("Access-Control-Allow-Headers", "Content-Type,X-Requested-With");
②Nodejsの背景
var http = require('http');
var server = http.createServer();
var qs = require('querystring');
server.on('request', function(req, res) {
var postData = '';
// 数据块接收中
req.addListener('data', function(chunk) {
postData += chunk;
});
// 数据接收完毕
req.addListener('end', function() {
postData = qs.parse(postData);
// 跨域后台设置
res.writeHead(200, {
'Access-Control-Allow-Credentials': 'true', // 后端允许发送Cookie
'Access-Control-Allow-Origin': 'http://www.domain1.com', // 允许访问的域(协议+域名+端口)
/*
* 此处设置的cookie还是domain2的而非domain1,因为后端也不能跨域写cookie(nginx反向代理可以实现),
* 但只要domain2中写入一次cookie认证,后面的跨域接口都能从domain2中获取cookie,从而实现所有的接口都能跨域访问
*/
'Set-Cookie': 'l=a123456;Path=/;Domain=www.domain2.com;HttpOnly' // HttpOnly的作用是让js无法读取cookie
});
res.write(JSON.stringify(postData));
res.end();
});
});
server.listen('8080');
console.log('Server is running at port 8080...');
③PHPの背景
<?php
header("Access-Control-Allow-Origin:*");
④Apacheはmod_headersモジュールを使用してHTTPヘッダー設定をアクティブ化する必要があります。これはデフォルトでアクティブ化されています。Apache構成ファイルの<Directory>、<Location>、<Files>、または<VirtualHost>の構成に次のコンテンツを追加するだけで済みます。
Header set Access-Control-Allow-Origin *