国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

關于跨域以及跨域的實現方式

崔曉明 / 2034人閱讀

摘要:關于跨域為什么會有跨域我們得先了解下同源策略。簡而言之,同協議同域名同端口號什么是跨域跨域就是采取技術方案突破同源策略的限制,實現不同域之間交互請求響應。

關于跨域 why?

為什么會有跨域?

我們得先了解下 ==同源策略(SOP, Same Origin Policy)==。

瀏覽器出于安全方面的考慮,只能訪問與包含它的頁面位于同一個域中的資源,該策略為通信設置了“相同的協議、相同的域、相同的端口”這一限制。試圖訪問上述限制之外的資源,都會引發安全錯誤。這種安全策略可以預防某些惡意行為。

簡而言之,

同協議 Same Protocol

同域名 Same Hostname

同端口號 Same Port

Same Protocol && Same Hostname && Same Port

What?

什么是跨域?

==跨域就是采取技術方案突破同源策略的限制,實現不同域之間交互(請求響應)。==

How?

那么如何實現跨域呢?
有以下幾種方法。

==方法一==

CORS (Cross-Origin Resource Sharing,跨域源資源共享),是一種ajax跨域請求資源的方式,支持現代瀏覽器,IE支持10以上,通過XMLHttpRequest實現Ajax通信的一個主要限制就是同源策略。
CORS是W3C的一個工作草案,定義了在必須訪問跨境資源時,瀏覽器和服務器該如何溝通。CORS的基本思想,就時使用自定義的HTTP頭部讓瀏覽器和服務器進行溝通,從而決定請求或者響應應該成功還是失敗。
實現思路:使用XMLHttpRequest發送請求時,瀏覽器會給該請求自動添加一個請求頭:Origin。服務器經過一系列處理,如果確定請求來源頁面屬于白名單,則在響應頭部加入首部字段:Access-Control-Allow-Origin。瀏覽器比較請求頭部的Origin 和響應頭部的 Access-Control-Allow-Origin是否一致,一致的話,瀏覽器得到響應數據。如果服務器沒有設置Access-Control-Allow-Origin 或者這個頭部源信息不匹配,瀏覽器就會駁回請求。

模擬CORS的實現

步驟1.

如何偽裝一個網站(在本地)?

1.編輯hosts文件

蘋果mac: 直接在git bash上輸入命令行操作即可 “sudo vi /etc.hosts” ,或者下載一些圖形界面應用軟件直接修改。

Windows操作系統:

win鍵(四個方塊的鍵)+ R = 彈開運行窗口

復制該文件路徑 c:windowssystem32driversetc

選中hosts文件,右鍵-屬性-安全-選擇組或用戶名(添加修改保存的權限的對象)- 編輯 - 再次選擇組或用戶名(添加修改保存的權限的對象 - 勾選權限(選項在此不表)

打開hosts文件,寫入 127.0.0.1 localhost;127.0.0.1 bai.com;127.0.0.1 google.com;可以寫入你任何你想模擬的網站,按照這種對應關系格式即可, ip地址+域名。

步驟2.
所需工具
node.js && git bash(模擬服務器),一個簡單的html頁面里面有個跨域請求的Ajax通信。





    
    Google
    


    

hello world

//nodeJS模擬后端響應CORS的實現
var http = require("http");
var fs = require("fs");
var url = require("url");
var path = require("path");

http.createServer(function(req, res){

     var urlObj = url.parse(req.url, true)

    switch (urlObj.pathname){

    case "/getNews":
    var news = ["NBA Break News","CBA Break News"]
    //CORS的實現
    res.setHeader("Access-Control-Allow-Origin","http://google.com:8080")
    /*res.setHeader("Access-Control-Allow-Origin","*")
    服務器設置公用接口
    */
    res.end(JSON.stringify(news));
    break;

    case "/" :
    if(urlObj.pathname == "/") {
        urlObj.pathname += "index.html"
    }

    default: 
    var filePath = path.join(__dirname, urlObj.pathname);
    fs.readFile(filePath,"binary", function(error, fileContent){
        if(error){
            console.log("404")
            res.writeHeader(404, "not found")
            res.end("

404,not found

") }else { res.write(fileContent, "binary") } }) } }).listen(8080);

上面代碼就是CORS實現的過程。

在本地修改hosts文件,127.0.0.1 google.com, 頁面的url為 http://google.com:8080。

在title為google的頁面上添加一個ajax請求,該請求以get方法會向baiduServer的端口("http://baidu.com:8080/getNews")發送一個請求。

瀏覽器會給請求頭加上Origin: http://google.com:8080, Request URL: http://baidu.com:8080/getNews。

baiduServer后端,響應頭添加首部字段。Access-Control-Allow-Origin: http://google.com:8080。 表明該服務器(baiduServer)接受請求并給予響應。

瀏覽器比較請求頭部的Origin 和響應頭部的 Access-Control-Allow-Origin是否一致,一致的話,瀏覽器得到響應數據。如果服務器沒有設置Access-Control-Allow-Origin: http://google.com:8080 或者這個頭部源信息不匹配,瀏覽器就會駁回請求。

當然服務器也可以設置公用接口, res.setHeader("Access-Control-Allow-Origin","*")

服務器設置公用接口, 任何人都可以使用該服務器這個端口的數據。


==方法二==

JSONP,是JSON with padding的簡寫(填充式JSON或參數式JSON)。

JSONP的原理,通過動態

nodeJS

var http = require("http");
var fs = require("fs");
var path = require("path");
var url = require("url");

http.createServer(function(req,res){
    var urlObj = url.parse(req.url, true);
    switch(urlObj.pathname) {
        case "/getNews" :
        var news = ["NBA Break News","CBA Break News"];
        res.setHeader("Content-Type","text/javascript; charset=utf-8");
        if(urlObj.query.newsData){
            var data = urlObj.query.newsData + "(" + JSON.stringify(news) + ")" ;
            res.end(data);
        } else {
            res.end(JSON.stringify(news))
        }
        break;

        case "/" :
        if(urlObj.pathname == "/") {
            urlObj.pathname +=  "index.html"
        }

        default:
            fs.readFile(path.join(__dirname, urlObj.pathname), function(error, data) {
                if(error) {
                    res.writeHeader(404, "not found");
                    res.end("

404, Not Found

"); } else { res.end(data) } }); }; }).listen(8080);

==方法三==

降域,主要應用場景是同一頁面下不同源的框架iframe請求

基于iframe實現的跨域,要求兩個域都必須屬于同一個基礎域, 比如 a.xx.com, b.xx.com,都有一個基礎域xx.com, 使用同一協議和端口,這樣在兩個頁面中同時添加documet.domain,就可以實現父頁面操控子頁面(框架)。

關于document.domain, 用來得到當前網頁的域名。在瀏覽器輸入URL,wwww.baidu.com。 http://wwww.baidu.com, document.domain 為 "www.baidu.com"。 也可以為document.domain賦值, 不過有限制,就是前面提到的,只能賦值為當前的域名或者基礎域名。
范例:

document.domain = "www.baidu.com" //successed 賦值成功, 當前域名。

document.domain = "baidu.com" // successed 賦值成功, 基礎域名。

但是下面的賦值會報錯(參數無效)。

"VM50:1 Uncaught DOMException: Failed to set the "domain" property on "Document": "a.baidu.com" is not a suffix of "www.baidu.com".

at :1:17"。

范例
document.domain = "google.com" // fail, 參數無效

document.domain = "a.baidu.com" // fail, 參數無效

因為google.com 和 a.baidu.com不是當前的域名,也不是當前域名的基礎域名。
原因: 瀏覽器為了防止惡意修改document.domain來實現跨域偷取數據。

-- --
==模擬降域的實現==

錯誤范例:

hosts 文件設置 win10系統路徑為 c:windowssystem32driversetchosts
127.0.0.1 a.com
127.0.0.1 b.com

a.com的一個網頁(a.html)里面 利用iframe引入一個b.com里的一個網頁(b.html )。在a.html里面可以看到b.html的內容,但不能用Javascript來操作它。
原因: 這兩個頁面屬于不同的域,在操作之前,瀏覽器會檢測兩個頁面的域是否相等,相等則允許操作,不相等則報錯。
這個例子里,不可能把a.html與b.html,利用JS改成同一個域。原因:兩個域的基礎域名不相等。

在http://a.com:8080/a.html的控制臺(console), 輸入代碼window.frames[0].document.body //VM150:1 Uncaught DOMException: Blocked a frame with origin "http://a.com:8080" from accessing a cross-origin frame.

at :1:18




    
    a.com:8080/a.html


    





    
    b.com:8080/b.html


    

this is b.html

//nodeJS 
var http = require("http");
var fs = require("fs");
var path = require("path");
var url = require("url");

http.createServer(function(req,res){
    var urlObj = url.parse(req.url, true);
    switch(urlObj.pathname) {
        case "/getNews" :
        var news = ["NBA Break News","CBA Break News"];
        res.setHeader("Content-Type","text/javascript; charset=utf-8");
        if(urlObj.query.newsData){
            var data = urlObj.query.newsData + "(" + JSON.stringify(news) + ")" ;
            res.end(data);
        } else {
            res.end(JSON.stringify(news))
        }
        break;

        case "/" :
        if(urlObj.pathname == "/") {
            urlObj.pathname +=  "index.html"
        }

        default:
            var filePath = path.join(__dirname, "static" ,urlObj.pathname);
            console.log(filePath)
            fs.readFile(filePath, function(error, data) {
                if(error) {
                    res.writeHeader(404, "not found");
                    res.end("

404, Not Found

"); } else { res.end(data) } }); }; }).listen(8080);

可以把iframe的src改變為"http://a.com:8080/b.html",這樣就可以了,是不會有這個問題的,因為域相等。
控制臺不會報錯,但是這樣沒完成跨域。可以使用html5中的postMessage來實現,針對基礎域不同的框架,這里暫且不表, 在方法四,會用到這種方法。

window.frames[0].document.body

?

?this is b.html ?

???




    
    a.com:8080/a.html


    
    

==正確范例:
降域的實現==

hosts文件設置

基礎域名相同

127.0.0.1 a.shawroc.com

127.0.0.1 b.shawroc.com

a.shawroc.com的里面一個網頁(a.html)引入b.shawroc.com里的一個網頁(b.html),a.shawroc.com還是不能操作b.shawroc.com里面的內容。
原因:document.domain不一樣,a.shawroc.com vs b.shawroc.com。
但是兩個頁面的基礎域名是一樣的,通過JS,將兩個頁面的domain改成一樣。
在a.html 和 b.html 里都加入

這樣在兩個頁面中同時添加document.domain, 就可以實現父頁面操控子頁面(框架)。

控制臺
window.frames[0].document.body
//console輸出


    

this is http://b.shawroc.com:8080/b.html

代碼




    
    a.shawroc.com:8080


    
    
    




    
    b.shawroc.com:8080/b.html


    

this is http://b.shawroc.com:8080/b.html

==方法四==

html5的postMessage API

html5引入的postMessage()方法,允許來自不同源的腳本采用異步方式進行有限的通信,可以實現跨文本檔、多窗口、跨域消息傳遞。

postMessage(data, origin) 方法,接受兩個參數。

1.data:要傳遞的數據,html5規范中提到該參數可以是JavaScript的任意基本類型或可復制的對象,然而并不是所有瀏覽器都做到了這點兒,部分瀏覽器只能處理字符串參數,所以我們在傳遞參數的時候需要使用JSON.stringify()方法對對象參數序列化,在低版本IE中引用json2.js可以實現類似效果。

2.origin:字符串參數,指明目標窗口的源,協議+主機+端口號[+URL],URL會被忽略,所以可以不寫,這個參數是為了安全考慮,postMessage()方法只會將message傳遞給指定窗口,當然如果愿意也可以建參數設置為"*",這樣可以傳遞給任意窗口,如果要指定和當前窗口同源的話設置為"/"。

范例

模擬postMessage的工作機制

改寫hosts文件

127.0.0.1 a.com

127.0.0.1 b.com






    
    a.com:8080


    




    
    b.shawroc.com:8080/b.html


    

this is http://b.com:8080/b.html

//nodeJS  模擬后端
var http = require("http");
var fs = require("fs");
var path = require("path");
var url = require("url");

http.createServer(function(req,res){
    var urlObj = url.parse(req.url, true);
    switch(urlObj.pathname) {
        case "/getNews" :
        var news = ["NBA Break News","CBA Break News"];
        res.setHeader("Content-Type","text/javascript; charset=utf-8");
        if(urlObj.query.newsData){
            var data = urlObj.query.newsData + "(" + JSON.stringify(news) + ")" ;
            res.end(data);
        } else {
            res.end(JSON.stringify(news))
        }
        break;

        case "/" :
        if(urlObj.pathname == "/") {
            urlObj.pathname +=  "index.html"
        }

        default:
            var filePath = path.join(__dirname, "postMessage" ,urlObj.pathname);
            fs.readFile(filePath, function(error, data) {
                if(error) {
                    res.writeHeader(404, "not found");
                    res.end("

404, Not Found

"); } else { res.end(data) } }); }; }).listen(8080);

解析代碼
步驟1, a.com:8080/a.html頁面下的input發生輸入事件時, 向目標窗口發一個MessageEvent事件