ホームページ > 記事 > ウェブフロントエンド > フロントエンドのクロスドメイン組織_html/css_WEB-ITnose
Web 開発の場合、ブラウザーの同一オリジン ポリシーにより、一部のハッキング手法はドメインを越えてリソースを取得するためによく使用されますが、ハッキング手法は常にハッキングです。 W3C が CORS 「クロスオリジン リソース共有」という標準を発表するまでは。
これにより、ブラウザーがクロスオリジン サーバーに XMLHttpRequest リクエストを発行できるようになり、AJAX が同じオリジンからのみ使用できるという制限が克服されます。
まず、互換性のために、CORS はブラウザーとサーバーの両方でサポートされている必要があります。主に ie10 以降であり、その他の最新のブラウザーもサポートされています。
http://caniuse.com/#feat=cors
CORS クロスドメインを使用する場合、プロセスは実際には通常の Ajax と同じですが、ブラウザーはこれがクロスであることを検出します。 -domain リクエストを行うと、検証などのいくつかの処理が自動的に行われるため、サーバーがサポートを提供している限り、フロントエンドは追加の処理を行う必要はありません。
CORS リクエストは、セキュリティのためにブラウザによって実行される処理の一部であり、ブラウザによって実行される動作も異なります。もちろん、追加の処理を行う必要はなく、ブラウザが自動的に処理します。
以下の 2 つの条件を同時に満たす限り、簡単なリクエストです。
1) 请求方法是以下三种方法中的一个:HEADGETPOST2)HTTP的头信息不超出以下几种字段:AcceptAccept-LanguageContent-LanguageLast-Event-IDContent-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
単純なクロスドメインリクエストの場合、ブラウザは自動的に情報を追加します。 Origin フィールドは、このリクエストの送信元 (プロトコル + ドメイン名 + ポート) を示します。サーバーはこの値を取得し、このリクエストに同意して返すかどうかを決定します。
// 请求GET /cors HTTP/1.1Origin: http://api.qiutc.meHost: api.alice.comAccept-Language: en-USConnection: keep-aliveUser-Agent: Mozilla/5.0...
サーバーがこのリクエストを許可すると、さらにいくつかのヘッダー フィールドを返します。
// 返回Access-Control-Allow-Origin: http://api.qiutc.meAccess-Control-Allow-Credentials: trueAccess-Control-Expose-Headers: InfoContent-Type: text/html; charset=utf-8Access-Control で始まるこれら 3 つのフィールドは、それぞれ次のことを表します。
応答ステータス コードは 200 である可能性があるため、このエラーは HTTP ステータス コードでは判断できません。
2. 非単純リクエスト
条件1) プリフライトリクエスト
ブラウザはまずサーバーに、現在の Web ページのドメイン名がサーバーの許可リストに含まれているかどうか、またどの HTTP 動詞とヘッダー情報フィールドを使用できるかを尋ねます。肯定的な応答を受信した場合にのみ、ブラウザは正式な XMLHttpRequest リクエストを発行します。それ以外の場合は、エラーが報告されます。
プリフライトリクエストの送信リクエスト:
“预检”请求用的请求方法是OPTIONS,表示这个请求是用来询问的。头信息里面,关键字段是Origin,表示请求来自哪个源。除了Origin字段,”预检”请求的头信息包括两个特殊字段。
Access-Control-Request-Headers
该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段,上例是X-Custom-Header。
预检请求的返回:
HTTP/1.1 200 OKDate: Mon, 01 Dec 2008 01:15:39 GMTServer: Apache/2.0.61 (Unix)Access-Control-Allow-Origin: http://api.qiutc.meAccess-Control-Allow-Methods: GET, POST, PUTAccess-Control-Allow-Headers: X-Custom-HeaderContent-Type: text/html; charset=utf-8Content-Encoding: gzipContent-Length: 0Keep-Alive: timeout=2, max=100Connection: Keep-AliveContent-Type: text/plain
Access-Control-Allow-Methods必需,它的值是逗号分隔的一个字符串,表明服务器支持的所有跨域请求的方法。注意,返回的是所有支持的方法,而不单是浏览器请求的那个方法。这是为了避免多次”预检”请求。
参考: 《跨域资源共享 CORS 详解》 http://www.ruanyifeng.com/blog/2016/04/cors.html
)
阮大神的文章,复制粘贴了不少。
jsonp = json + padding
其实对于常用性来说,jsonp应该是使用最经常的一种跨域方式了,他不受浏览器兼容性的限制。但是他也有他的局限性,只能发送 GET 请求,需要服务端和前端规定好,写法丑陋。
它的原理在于浏览器请求 script 资源不受同源策略限制,并且请求到 script 资源后立即执行。
主要做法是这样的:
在浏览器端:
首先全局注册一个callback回调函数,记住这个函数名字(比如:resolveJson),这个函数接受一个参数,参数是期望的到的服务端返回数据,函数的具体内容是处理这个数据。
然后动态生成一个 script 标签,src 为:请求资源的地址+获取函数的字段名+回调函数名称,这里的获取函数的字段名是要和服务端约定好的,是为了让服务端拿到回调函数名称。(如: www.qiute.com?callbackName=resolveJson )。
function resolveJosn(result) { console.log(result.name);}var jsonpScript= document.createElement("script");jsonpScript.type = "text/javascript";jsonpScript.src = "http://www.qiute.com?callbackName=resolveJson";document.getElementsByTagName("head")[0].appendChild(jsonpScript);
服务端
在接受到浏览器端 script 的请求之后,从url的query的callbackName获取到回调函数的名字,例子中是 resolveJson 。
然后动态生成一段javascript片段去给这个函数传入参数执行这个函数。比如:
resolveJson({name: 'qiutc'});
执行服务端返回这个 script 之后,浏览器端获取到 script 资源,然后会立即执行这个 javascript,也就是上面那个片段。这样就能根据之前写好的回调函数处理这些数据了。
在一些第三方库往往都会封装jsonp的操作,比如 jQuery 的 $.getJSON 。
一个页面框架(iframe/frame)之间(父子或同辈),是能够获取到彼此的window对象的,但是这个 window 不能拿到方法和属性(尼玛这有什么用,甩脸)。
// 当前页面域名 http://blog.qiutc.me/a.html<script>function onLoad() { var iframe =document.getElementById('iframe'); var iframeWindow = iframe.contentWindow; // 这里可以获取 iframe 里面 window 对象,但是几乎没用 var doc = iframeWindow.document; // 获取不到}</script><iframe src="http://www.qiutc.me/b.html" onload="onLoad()"</iframe>
这个时候, document.domain 就可以派上用场了,我们只要把 http://blog.qiutc.me/a.html 和 http://www.qiutc.me/b.html 这两个页面的 document.domain 都设成相同的域名就可以了。
前提条件:这两个域名必须属于同一个基础域名!而且所用的协议,端口都要一致。
但要注意的是, document.domain 的设置是有限制的,我们只能把 document.domain 设置成自身或更高一级的父域,且主域必须相同。例如: a.b.example.com 中某个文档的 document.domain 可以设成 a.b.example.com 、 b.example.com 、 example.com 中的任意一个,但是不可以设成 c.a.b.example.com ,因为这是当前域的子域,也不可以设成 baidu.com ,因为主域已经不相同了。
这样我们就可以通过js访问到iframe中的各种属性和对象了。
// 主页面:http://blog.qiutc.me/a.html<script>document.domain = 'qiutc.me';function onLoad() { var iframe =document.getElementById('iframe'); var iframeWindow = iframe.contentWindow; // 这里可以获取 iframe 里面 window 对象并且能得到方法和属性 var doc = iframeWindow.document; // 获取到}</script><iframe src="http://www.qiutc.me/b.html" onload="onLoad()"</iframe>
// iframe 里面的页面<script>document.domain = 'qiutc.me';</script>
window对象有个name属性,该属性有个特征:即在一个窗口(window)的生命周期内,窗口载入的所有的页面都是共享一个 window.name 的,每个页面对 window.name 都有读写的权限, window.name 是持久存在一个窗口载入过的所有页面中的,并不会因新页面的载入而进行重置。
比如有一个 www.qiutc.me/a.html 页面,需要通过a.html页面里的js来获取另一个位于不同域上的页面 www.qiutc.com/data.html 里的数据。
data.html页面里的代码很简单,就是给当前的window.name设置一个a.html页面想要得到的数据值。data.html里的代码:
<script>window.name = '我是被期望得到的数据';</script>
那么在 a.html 页面中,我们怎么把 data.html 页面载入进来呢?显然我们不能直接在 a.html 页面中通过改变 window.location 来载入data.html页面(这简直扯蛋)因为我们想要即使 a.html 页面不跳转也能得到 data.html 里的数据。
答案就是在 a.html 页面中使用一个隐藏的 iframe 来充当一个中间人角色,由 iframe 去获取 data.html 的数据,然后 a.html 再去得到 iframe 获取到的数据。
充当中间人的 iframe 想要获取到 data.html 的通过 window.name 设置的数据,只需要把这个 iframe 的src设为 www.qiutc.com/data.html 就行了。然后 a.html 想要得到 iframe 所获取到的数据,也就是想要得到 iframe 的 window.name 的值,还必须把这个 iframe 的 src 设成跟 a.html 页面同一个域才行,不然根据前面讲的同源策略, a.html 是不能访问到 iframe 里 的window.name 属性的。这就是整个跨域过程。
// a.html<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Document</title> <script> function getData() { var iframe =document.getElementById('iframe'); iframe.onload = function() { var data = iframe.contentWindow.name; // 得到 } iframe.src = 'b.html'; // 这里b和a同源 } </script></head><body> <iframe src="http://www.qiutc.com/data.html" style="display:none" onload="getData()"</iframe></body></html>
window.postMessage(message, targetOrigin) 方法是html5新引进的特性,可以使用它来向其它的window对象发送消息,无论这个window对象是属于同源或不同源。兼容性:
http://caniuse.com/#search=postMessage
调用postMessage方法的window对象是指要接收消息的那一个window对象,该方法的第一个参数message为要发送的消息,类型只能为字符串;第二个参数targetOrigin用来限定接收消息的那个window对象所在的域,如果不想限定域,可以使用通配符 * 。
需要接收消息的window对象,可是通过监听自身的message事件来获取传过来的消息,消息内容储存在该事件对象的data属性中。
上面所说的向其他window对象发送消息,其实就是指一个页面有几个框架的那种情况,因为每一个框架都有一个window对象。在讨论第种方法的时候,我们说过,不同域的框架间是可以获取到对方的window对象的,虽然没什么用,但是有一个方法是可用的- window.postMessage 。下面看一个简单的示例,有两个页面:
// 主页面 blog.qiutc.com<script>function onLoad() { var iframe =document.getElementById('iframe'); var iframeWindow = iframe.contentWindow; iframeWindow.postMessage("I'm message from main page.");}</script><iframe src="http://www.qiutc.me/b.html" onload="onLoad()"</iframe>
// b 页面<script>window.onmessage = function(e) { e = e || event; console.log(e.data);}</script>
一种用 CSS 跨域传输文本的方案。
优点:相比 JSONP 更为安全,不需要执行跨站脚本。
缺点:没有 JSONP 适配广,CSST 依赖支持 CSS3 的浏览器。
原理:通过读取 CSS3 content 属性获取传送内容。
具体可以参考: CSST (CSS Text Transformation)
flash 嘛,这个东西注定灭亡,不想说了。。。