說一說javascript跨域和jsonp

来源:http://www.cnblogs.com/kongxianghai/archive/2016/04/03/5350079.html
-Advertisement-
Play Games

同源策略 在瀏覽器的安全策略中“同源策略”非常如雷貫耳,說的是協議、功能變數名稱、埠相同則視為同源,功能變數名稱也可換成IP地址,不同源的頁面腳本不能獲取對方的數據。 要是想使用XMLHttpRequest或者常規的AJAX請求獲取另一個站點的數據,瀏覽器會告訴你“XXXX is not allowed by A ...


同源策略

在瀏覽器的安全策略中“同源策略”非常如雷貫耳,說的是協議、功能變數名稱、埠相同則視為同源,功能變數名稱也可換成IP地址,不同源的頁面腳本不能獲取對方的數據。

要是想使用XMLHttpRequest或者常規的AJAX請求獲取另一個站點的數據,瀏覽器會告訴你“XXXX is not allowed by Access-Control-Allow-Orign”.

因為同源策略的存在,防止了跨域訪問的安全問題,但同時也損失了方便獲取資源的便利。

 

跨域的src屬性 

世事又非絕對,瀏覽器還是允許幾個元素跨域訪問外部資源的,如:<script>,<img>,<iframe>,也就是說,在html元素中擁有src屬性的元素是可以跨域訪問資源。

通過src屬性,img可以引用其它站點或圖床的圖片,大大降低本站的圖片持久。

通過src屬性,script可以引用CDN的JS文件,加速了瀏覽器的腳本文件的下載,跨域的數據獲取更加高效和方便。

通過src屬性,iframe可以嵌入其它站點的頁面,可以讓頁面的框架和可變內容分離,內容引用較為靈活,方便引用其它站點,雖然現在越來越不建議使用它。

正因為跨域訪問的存在,web世界才能更加的精彩。

而JSONP正式利用了script標簽的跨域能力。

 

JSONP 

全名JSON with padding

就是通過約定,訪問跨域伺服器上數據的方法。

這種約定其實就是一個函數定義,並且具備數據參數的定義,由跨域伺服器的腳本或動態生成的腳本調用並且傳遞數據參數。

該函數稱之為“跨域回調函數”。

1.一個簡單的跨域腳本調用

本地伺服器上的一個腳本,直接引用了跨域伺服器上的腳本文件。

<html>
<head>
    <title>test</title>
</head>
<body>
    <script src="http://localhost:3001/javascripts/jsonpsrc1.js"></script>
</body>
</html>

跨域伺服器上的腳本jsonpsrc1.js

alert('hi 我們不是一個域的哦');

運行後,瀏覽器訪問本地伺服器上的頁面,會彈出alert

 

2.跨域傳遞數據

在本地伺服器的腳本中,約定一個函數,名為jsonpCallback跨域回調函數交由跨域伺服器上的腳本調用。

註意,jsonpCallback跨域回調函數的定義必須是在引用跨域伺服器上的腳本之前。

<html>
<head>
    <title>test</title>
</head>
<body>
<script>
    function jsonpCallback(data){
        alert(JSON.stringify(data,null,2));
    }
</script>
<script src="http://localhost:3001/javascripts/jsonpsrc2.js"></script>
</body>
</html>

跨域伺服器上的腳本jsonpsrc2.js,按照約定的跨域回調函數名調用,並傳遞一個數據對象。

jsonpCallback({
    name:'白色的海',
    age:90
});

運行後,瀏覽器訪問本地伺服器上的頁面,會彈出alert,顯示跨域伺服器傳遞過來的數據。

 

3.動態跨域回調函數

通過上面的2種方法已經基本實現了JSONP的使用,但是還存在一個問題,就是必須要提前約定這個跨域回調函數的名字 。

每次都要按照跨域伺服器上的的回調函數名進行定義,極為不便。

那麼兩個跨域的腳本引用能否不綁定同一個函數名稱呢。

可以在本地伺服器腳本中任意定義跨域回調函數的名稱,將該函數名用過參數請求給跨域伺服器,在跨域伺服器後臺代碼上動態拼接生成回調函數的調用字元串並響應給請求方。

在這裡是用node.js+express的運行環境,並且以一個簡單的查詢航班信息的跨域請求進行簡單的實現。

在本地伺服器頁面腳本中定義了showFlightInfo跨域回調函數,用於顯示跨域伺服器返回的航班信息。

在其後的script標簽中對跨域伺服器進行了一個JS的請求,並將航班信息和跨域回調函數名帶過去。

<html>
<head>
    <title>test</title>
    <link rel="stylesheet" href="/stylesheets/style.css">
</head>
<body>
    <h1>航班信息</h1>
    <h1>某航</h1>
    <script>
        function showFlightInfo(data){
            var flightNoEle = document.createElement('h4');
            flightNoEle.innerHTML=data.flightNo;

            var fromEle = document.createElement('h4');
            fromEle.innerHTML=data.from;

            var toEle = document.createElement('h4');
            toEle.innerHTML=data.to;

            document.body.appendChild(flightNoEle);
            document.body.appendChild(fromEle);
            document.body.appendChild(toEle);
        }
    </script>
    <script src="http://localhost:3001/info/flight?flightNo=MU531&callbackFunc=showFlightInfo"></script>
</body>
</html>

跨域伺服器的後臺代碼中響應JS請求,接收航班號,生成航班信息,連同跨域回調函數名稱拼接成JS字元串後響應請求方。

router.get('/info/flight', function (req, res) {
    //生成航班信息,這裡直接拿請求過來的航班號寫一個航班信息對象
    var data = {
        flightNo: req.query.flightNo,
        from: '北京',
        to: '上海'};

    //獲取請求過來的跨域回調函數名稱
    var callbackFunc = req.query.callbackFunc;

    //拼成一個JS字元串
    var s = callbackFunc + '(' + JSON.stringify(data, null, 2) + ');';
    console.log(s);

    //通過設置http的header,告知請求方響應的內容是JS腳本
    res.setHeader('content-type', 'text/javascirpt;charset=utf-8');
    //res.setHeader('content-language', 'zh-CN')
    res.write(s);
    res.end();

});

運行後,瀏覽器訪問本地伺服器上的頁面,會顯示跨域伺服器上傳遞過來的航班信息。

為了看得清,將跨域伺服器收到的請求和響應的內容輸出到控制台,方便查看。

第一行是收到的請求,後面的是對請求的響應,可以看到跨域服務端返回給請求方一個JS的腳本,其中的回調函數名稱是請求方定製的。

 如此完成JSONP的基本實現。

 

不只是JSONP

通過跨域請求獲取數據本質上是利用了<script>標簽的src屬性,通過瀏覽器將跨域的腳本拉過來並同時執行。

那麼既然是拉過來執行,那和本頁面中的其它腳本的執行沒多大區分,那就當然也可以通過生成html元素和css的方式改變頁面的顯示內容,以實現更豐富的功能,比如廣告。

基於上面的航班信息,我要在其中顯示一塊廣告內容,內容來自於跨域伺服器。

通過<script>標簽引用跨域伺服器上對應的廣告資源地址

<html>
<head>
    <title>test</title>
    <link rel="stylesheet" href="/stylesheets/style.css">
</head>
    <body>
        <h1>航班信息</h1>
        <script src="http://localhost:3001/ad"></script>
        <h1>某航</h1>
        <script>
            function showFlightInfo(data){
                var flightNoEle = document.createElement('h4');
                flightNoEle.innerHTML=data.flightNo;
    
                var fromEle = document.createElement('h4');
                fromEle.innerHTML=data.from;
    
                var toEle = document.createElement('h4');
                toEle.innerHTML=data.to;
    
                document.body.appendChild(flightNoEle);
                document.body.appendChild(fromEle);
                document.body.appendChild(toEle);
            }
        </script>
        <script src="http://localhost:3001/info/flight?flightNo=MU531&amp;callbackFunc=showFlightInfo"></script>
    </body>
</html>

跨域伺服器的後臺代碼中響應JS請求,生成一串使用document.write向頁面中生成html元素的字元串。

router.get('/ad', function (req, res) {
    //拼接一JS字元串,完成向html頁面中輸出html標記
    var s = 'document.write(\'<div style="background-color:red;width:10rem;height:10rem">我是旅行社廣告</div>\');';
    console.log(s);

    res.setHeader('content-type', 'text/javascirpt;charset=utf-8');
    res.write(s);
    res.end();
});

運行後,瀏覽器訪問本地伺服器上的頁面,會在航班信息下方顯示紅色廣告位,而這個廣告位完全是跨域伺服器生成的並且包括樣式。

在此基礎上,可以做出很多效果,包括將頁面某一部分的生成交給專門的或者對應的業務伺服器上完成。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 基礎知識(包括但不限於:二叉查找樹是啥,SBT又是啥反正又不能吃,平衡樹怎麼旋轉,等等)在這裡就不(lan)予(de)贅(duo)述(xie)了。 由於學生黨比較忙,所以博文寫的比較簡略,有時間會慢慢補完 先貼代碼: 1 int seed; 2 int _rand() 3 { 4 return se ...
  • 2nd
    02.01_Java語言基礎(常量的概述和使用)(掌握) A:什麼是常量 在程式執行的過程中其值不可以發生改變 B:Java中常量的分類 字面值常量 自定義常量(面向對象部分講) C:字面值常量的分類 字元串常量 用雙引號括起來的內容 整數常量 所有整數 小數常量 所有小數 字元常量 用單引號括起來 ...
  • ggg fffffffffffffffffffffffffffffffffffffffffffffff ...
  • 遍歷List的多種方式 在講如何線程安全地遍歷List之前,先看看通常我們遍歷一個List會採用哪些方式。 方式一: 方式二: 方式三: 方式四(Java 8): 方式五(Java 8 Lambda): 首先,方式一的遍歷方法是一種非常不建議使用的方式,特別是對於LinkedList。LinkedL ...
  • 輸出:用print()在括弧中加上字元串,就可以向屏幕上輸出指定的文字。比如輸出'hello, world',用代碼實現如下>>>print('hello,world') 也可以是多個字元串,中間用逗號鏈接‘;代碼實現如下>>>print('The quick bronw fox','jumps o ...
  • 原文鏈接:http://www.orlion.ga/207/ 一、代理模式 代理模式是經常用到的設計模式,代理模式是給指定對象提供代理對象。由代理對象來控制具體對象的引用。 代理模式涉及到的角色: 抽象主題角色:聲明瞭代理主題和真實主題的公共介面,使任何需要真實主題的地方都能用代理主題代替。 代理主 ...
  • 剛拜讀 @Learning hard 的 [Asp.net 開發系列之SignalR篇]專題一:Asp.net SignalR快速入門 跟著博文一步步操作,這是新人的學習方式 然而筆者的開發環境和 @Learning hard 的有所不同,導致出現了一些小的問題! 筆者環境 VS2013 + .ne ...
  • × 目錄 [1]變形原點 [2]變形函數 [3]多值 前面的話 CSS變形transform是一些效果的集合,主要是移動、旋轉、縮放和傾斜這四種基本操作,還可以通過設置matrix矩陣來實現更複雜的效果。變形transform可以實現2D和3D兩種效果。2D變形涉及的屬性主要有transform變形 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...