Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 久久频道毛片免费不卡片,韩国免费啪啪漫画无遮拦免费,欧美啪啪网址

          整合營銷服務(wù)商

          電腦端+手機端+微信端=數(shù)據(jù)同步管理

          免費咨詢熱線:

          教你如何使用JSONP實現(xiàn)跨域

          教你如何使用JSONP實現(xiàn)跨域

          么是跨域?

          簡單的來說,出于安全方面的考慮,頁面中的JavaScript無法訪問其他服務(wù)器上的數(shù)據(jù),即“同源策略”。而跨域就是通過某些手段來繞過同源策略限制,實現(xiàn)不同服務(wù)器之間通信的效果。

          什么是JSONP?

          JSON(JavaScript Object Notation) 是一種輕量級的數(shù)據(jù)交換格式,JSONP 是 JSON with padding(填充式 JSON 或參數(shù)式 JSON)的簡寫。JSONP(JSON with Padding)則是JSON 的一種“使用模式”,通過這種模式可以實現(xiàn)數(shù)據(jù)的跨域獲取。JSONP 由兩部分組成:回調(diào)函數(shù)和數(shù)據(jù)。回調(diào)函數(shù)是當響應(yīng)到來時應(yīng)該在頁面中調(diào)用的函數(shù)。回調(diào)函數(shù)的名字一般是在請求中指定的。而數(shù)據(jù)就是傳入回調(diào)函數(shù)中的 JSON 數(shù)據(jù)。

          JSONP跨域的基本原理

          在同源策略下,在某個服務(wù)器下的頁面是無法獲取到該服務(wù)器以外的數(shù)據(jù)的,但img、iframe、script等標簽是個例外,這些標簽可以通過src屬性請求到其他服務(wù)器上的數(shù)據(jù)。利用script標簽的開放策略,我們可以實現(xiàn)跨域請求數(shù)據(jù),當然,也需要服務(wù)端的配合。當我們正常地請求一個JSON數(shù)據(jù)的時候,服務(wù)端返回的是一串JSON類型的數(shù)據(jù),而我們使用JSONP模式來請求數(shù)據(jù)的時候,服務(wù)端返回的是一段可執(zhí)行的JavaScript代碼。

          舉個例子,假如需要從服務(wù)器(http://www.a.com/user?id=123)獲取的數(shù)據(jù)如下:

          1. {"id": 123, "name" : 張三, "age": 17}

          那么,使用JSONP方式請求(http://www.a.com/user?id=123?callback=foo)的數(shù)據(jù)將會是如下:

          1. foo({"id": 123, "name" : 張三, "age": 17});

          當然,如果服務(wù)端考慮得更加充分,返回的數(shù)據(jù)可能如下:

          1. try{foo({"id": 123, "name" : 張三, "age": 17});}catch(e){}

          這時候我們只要定義一個foo()函數(shù),并動態(tài)地創(chuàng)建一個script標簽,使其的src屬性為http://www.a.com/user?id=123?callback=foo:

          便可以使用foo函數(shù)來調(diào)用返回的數(shù)據(jù)了。

          JSONP跨域原理探秘

          我們知道,使用 XMLHTTPRequest 對象發(fā)送HTTP請求時,會遇到 同源策略 問題,域不同請求會被瀏覽器攔截。

          那么是否有方法能繞過 XMLHTTPRequest 對象進行HTTP跨域請求呢?

          換句話說,不使用 XMLHTTPRequest 對象是否可以發(fā)送跨域HTTP請求呢?

          細心的你可能會發(fā)現(xiàn),像諸如:

          <script type="text/javascript" src="http://www.a.com/scripts/1.js"></script>

          <img src="http://www.b.com/images/1.jpg" />

          <link rel="stylesheet" />

          這種標簽是不會遇到"跨域"問題的,嚴格意義上講,這不是跨域,跨域是指在腳本代碼中向非同源域發(fā)送HTTP請求,這只是跨站資源請求。

          那么,我們是否可以利用跨站資源請求這一方式來實現(xiàn)跨域HTTP請求呢?

          以<script></script>標簽為例進行探索,先看一段代碼:

          <!DOCTYPE html>

          <html>

          <head>

          <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

          <title>jsonp demo</title>

          <!-- JavaScript片斷1 -->

          <script type="text/javascript">

          function handler(data) {

          alert(data);

          // our code here...

          }

          </script>

          <!-- JavaScript片斷2 -->

          <script type="text/javascript">

          handler('success');

          </script>

          </head>

          <body>

          A JSONP demo.

          </body>

          </html>

          這段代碼中,有2個JavaScript片斷,第1個片斷中定義了一個處理函數(shù)handler(),這個處理函數(shù)比較簡單,沒有對數(shù)據(jù)做任何處理,只是把它alert出來;第2個片斷調(diào)用了它,運行這個頁面瀏覽器會彈出"success"。

          我們假設(shè)第2個JavaScript片斷存儲在別的地方,然后我們使用<script src="" />的方式把它引入進來,像這樣:

          <!DOCTYPE html>

          <html>

          <head>

          <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

          <title>jsonp demo</title>

          <!-- JavaScript片斷1 -->

          <script type="text/javascript">

          function handler(data) {

          alert(data);

          // our code here...

          }

          </script>

          <!-- JavaScript片斷2 -->

          <script type="text/javascript" src="http://service.a.com/script/1.js"></script>

          </head>

          <body>

          A JSONP demo.

          </body>

          </html>

          service.a.com/script/1.js:

          handler('success');

          這種方法和把JavaScript代碼直接寫在頁面是等效的,但是,我們由此可以聯(lián)想到什么?

          我們是否可以事先在本頁面定義處理程序,服務(wù)端返回JS腳本,腳本的內(nèi)容就是對處理程序的回調(diào),服務(wù)返回的數(shù)據(jù)通過參數(shù)的形式傳回:

          handler('服務(wù)返回的數(shù)據(jù)');

          然后通過動態(tài)向當前頁面head節(jié)點添加<script src="服務(wù)地址"></script>節(jié)點的方式來“偽造”HTTP請求?

          于是,可以編寫這樣一個簡單的測試用例:

          先寫服務(wù)端,非常簡單的一個服務(wù),返回字符串"Hello World",一般處理程序Service.ashx:

          using System;

          using System.Collections.Generic;

          using System.Linq;

          using System.Web;

          namespace JSONPDemo.Service

          {

          /// <summary>

          /// Service2 的摘要說明

          /// </summary>

          public class Service2 : IHttpHandler

          {

          public void ProcessRequest(HttpContext context)

          {

          context.Response.ContentType="text/plain";

          context.Response.Write("handler('Hello World');");

          }

          public bool IsReusable

          {

          get

          {

          return false;

          }

          }

          }

          }

          再寫客戶端,一個簡單的靜態(tài)Web頁,index.html:

          <!DOCTYPE html>

          <html>

          <head>

          <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>

          <title></title>

          <script type="text/javascript">

          // 跨域發(fā)送HTTP請求,從服務(wù)端獲取字符串"Hello World"

          function getHello() {

          var script=document.createElement('script');

          script.setAttribute('src', 'http://localhost:8546/Service.ashx');

          document.querySelector("head").appendChild(script);

          }

          // 處理函數(shù)

          function handler(data) {

          alert(data);

          // our code here...

          }

          </script>

          </head>

          <body>

          <input type="button" value="發(fā)送跨域HTTP請求,獲取Hello World" onclick="getHello()" />

          </body>

          </html>

          測試成功!

          在這個測試例子中,我們使用一般處理程序編寫了一個簡單的返回Hello World的服務(wù),然后使用動態(tài)創(chuàng)建<script></script>節(jié)點的方式實現(xiàn)了跨域HTTP請求。

          由于<script>、<img>標簽資源請求是異步的,所以我們就實現(xiàn)了一個跨域的異步HTTP請求。

          但是這么做是不夠的,一個頁面可能會有多個HTTP請求,而上面這個示例的處理程序只有一個——handler。

          不同的請求應(yīng)該由不同的處理程序來處理,對上面的代碼稍做修改,只需要給<script>標簽的src屬性中的URL添加一個參數(shù)來指定回調(diào)函數(shù)的名稱就可以了:

          服務(wù)端:

          public void ProcessRequest(HttpContext context)

          {

          context.Response.ContentType="text/plain";

          // 前端指定的回調(diào)函數(shù)名稱

          var callbackFuncName=context.Request.QueryString["callback"];

          var responseData="Hello World";

          // 回調(diào)腳本,形如:handler('responseData');

          var scriptContent=string.Format("{0}('{1}');", callbackFuncName, responseData);

          context.Response.Write(scriptContent);

          }

          Web客戶端:

          <!DOCTYPE html>

          <html>

          <head>

          <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>

          <title>jsonp demo</title>

          <script type="text/javascript">

          // 跨域發(fā)送HTTP請求,從服務(wù)端獲取字符串"Hello World"

          function getHello() {

          var script=document.createElement('script');

          script.setAttribute('src', 'http://localhost:8546/Service.ashx?callback=handler');//callback指定回調(diào)函數(shù)名稱

          document.querySelector("head").appendChild(script);

          }

          // 處理函數(shù)

          function handler(data) {

          alert(data);

          // our code here...

          }

          </script>

          </head>

          <body>

          <input type="button" value="發(fā)送跨域HTTP請求,獲取Hello World" onclick="getHello()" />

          </body>

          </html>

          使用jQuery的JSONP跨域

          jQuery的ajax方法對JSONP式跨域進行了封裝,如果使用jQuery進行JSONP原理式的跨域HTTP請求,將會變得非常簡單:

          <!DOCTYPE html>

          <html>

          <head>

          <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>

          <title>jQuery jsonp demo</title>

          <script src="jquery-1.11.0.min.js"></script>

          <script type="text/javascript">

          $.ajax({

          type: "get",

          async: false,

          url: "http://localhost:8546/Service.ashx",

          dataType: "jsonp",

          success: function (data) {

          alert(data);

          },

          error: function () {

          alert('fail');

          }

          });

          </script>

          </head>

          <body>

          使用jQuery一切將會變得非常簡單。

          </body>

          </html>

          只需要將dataType設(shè)置為"jsonp"就可以進行跨域請求了,一切就像發(fā)送非跨域請求那樣簡單。

          jQuery為我們封裝好了回調(diào)函數(shù),一般情況下不需要我們單獨去寫,如果你不想在success中處理,想單獨寫處理函數(shù),那么可以通過設(shè)置這2個參數(shù)來實現(xiàn):

          • jsonp: "callback",//傳遞給服務(wù)端的回調(diào)函數(shù)名稱參數(shù),如果不設(shè)置此項,則默認是"callback"
          • jsonpCallback: "handler",//傳遞給服務(wù)端的回調(diào)函數(shù)名稱,如果不設(shè)置此項,則默認是形如"jQuery111007837897759742043_1460657212499"的由jQuery自動生成的函數(shù)名稱

          必須要強調(diào)的是:

          1.JSONP雖然看起來很像一般的ajax請求,但其原理不同,JSONP是對文章第一小節(jié)原理的封裝,是通過<script>標簽的動態(tài)加載來實現(xiàn)的跨域請求,而一般的ajax請求是通過XMLHttpRequest對象進行;

          2.JSONP不是一種標準協(xié)議,其安全性和穩(wěn)定性都不如 W3C 推薦的 CORS;

          3.JSONP不支持POST請求,即使把請求類型設(shè)置為post,其本質(zhì)上仍然是一個get請求。

          、使用跨文檔消息傳遞(Cross-document Messaging)

          可以在不同窗口或iframe之間安全地傳遞消息,即使這些窗口或iframe來自不同的域。以下是使用window.postMessage()方法進行跨域消息傳遞的基本示例:

          假設(shè)有兩個頁面:page1.html和page2.html,它們分別位于不同的域。

          在page1.html中,我們想要向page2.html發(fā)送消息:

          <!-- page1.html -->
          
          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <meta name="viewport" content="width=device-width, initial-scale=1.0">
              <title>Page 1</title>
          </head>
          <body>
              <button id="sendMessageBtn">Send Message to Page 2</button>
          
              <script>
                  const sendMessageBtn=document.getElementById('sendMessageBtn');
          
                  // 監(jiān)聽按鈕點擊事件
                  sendMessageBtn.addEventListener('click', function() {
                      // 獲取目標窗口的引用
                      const targetWindow=window.parent.frames['page2-frame'];
          
                      // 向目標窗口發(fā)送消息
                      targetWindow.postMessage('Hello from Page 1!', 'http://www.example.com/page2.html');
                  });
              </script>
          </body>
          </html>
          

          在page2.html中,我們接收來自page1.html的消息:

          <!-- page2.html -->
          
          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <meta name="viewport" content="width=device-width, initial-scale=1.0">
              <title>Page 2</title>
          </head>
          <body>
              <iframe src="http://www.example.com/page1.html" name="page1-frame" id="page1-frame"></iframe>
          
              <script>
                  // 監(jiān)聽來自其他窗口的消息
                  window.addEventListener('message', function(event) {
                      // 判斷消息來源是否是預(yù)期的域
                      if (event.origin==='http://www.example.com') {
                          // 處理收到的消息
                          console.log('Received message from Page 1:', event.data);
                      }
                  });
              </script>
          </body>
          </html>
          

          page1.html包含一個按鈕,當點擊按鈕時,會向page2.html發(fā)送消息。page2.html中通過監(jiān)聽window對象的message事件來接收來自page1.html的消息,并且只有當消息的來源是預(yù)期的域時才會處理該消息。

          需要注意的是,跨文檔消息傳遞僅在現(xiàn)代瀏覽器中得到支持,且需要發(fā)送消息的窗口或iframe引用以及目標窗口的域。以前的IE瀏覽器啥的是不支持的。這種方式較為簡單,方便初學(xué)者進行測試。

          二、還有一種辦法較為復(fù)雜,可以利用代理服務(wù)器,通過在同一域下設(shè)置一個代理服務(wù)器,將跨域請求發(fā)送到該代理服務(wù)器上,再由代理服務(wù)器轉(zhuǎn)發(fā)請求到目標服務(wù)器。這種方法需要在服務(wù)器端實現(xiàn)代理,但可以繞過瀏覽器的跨域限制。

          另外還有兩種較為簡單的方式也做一下介紹,下面這2種方式是常用的方式了,較為簡單,

          三、JSONP(JSON with Padding):JSONP是一種利用<script>標簽的GET請求實現(xiàn)跨域數(shù)據(jù)傳輸?shù)募夹g(shù)。它允許從其他域加載數(shù)據(jù),但只支持GET請求,且需要目標服務(wù)器支持返回JavaScript回調(diào)函數(shù)。JSONP的缺點是安全性較低,僅能進行GET請求。

          四、CORS(Cross-Origin Resource Sharing):CORS是一種現(xiàn)代的跨域資源共享機制,它允許服務(wù)器端設(shè)置HTTP頭部,以允許在不同域之間的安全數(shù)據(jù)傳輸。通過在服務(wù)器端配置,可以允許跨域請求發(fā)送和接收數(shù)據(jù)。

          五、WebSocket:得利于HTML5技術(shù)的發(fā)展,現(xiàn)在主流瀏覽器的支持,WebSocket是HTML5提供的一種在單個TCP連接上進行全雙工通訊的協(xié)議,它可以與任意域的服務(wù)器進行通訊,但需要服務(wù)器端支持WebSocket協(xié)議。

          在客戶端,我們可以使用JavaScript來創(chuàng)建WebSocket連接:

          // 客戶端代碼
          const socket=new WebSocket('ws://example.com:8080'); // 替換為實際的WebSocket服務(wù)器地址
          
          // 當WebSocket連接成功建立時觸發(fā)
          socket.onopen=function(event) {
              console.log('WebSocket連接已建立');
              
              // 向服務(wù)器發(fā)送數(shù)據(jù)
              socket.send('Hello from client!');
          };
          
          // 當接收到來自服務(wù)器的消息時觸發(fā)
          socket.onmessage=function(event) {
              console.log('Received message from server:', event.data);
          };
          
          // 當發(fā)生錯誤時觸發(fā)
          socket.onerror=function(error) {
              console.error('WebSocket發(fā)生錯誤:', error);
          };
          
          // 當WebSocket連接關(guān)閉時觸發(fā)
          socket.onclose=function(event) {
              console.log('WebSocket連接已關(guān)閉');
          };
          

          在服務(wù)器端,您需要使用相應(yīng)的語言和框架來創(chuàng)建WebSocket服務(wù)器。以下是一個簡單的Node.js示例:

          家好,我是前端西瓜哥。今天講 JSONP。

          JSONP,是 JSON with Padding 的縮寫,字面上的意思就是 “填充 JSON”。JSONP 是解決跨域請求的一種方案,我們先了解下跨域請求是什么。

          跨域

          瀏覽器在跨域發(fā)送 Ajax/fetch 請求時,會觸發(fā)瀏覽器的同源策略,導(dǎo)致請求失敗。

          只要協(xié)議、域名、端口有一個不同,那瀏覽器就會認為是跨域。比如你在 a.com 下通過 Ajax 請求 b.com/api/book,默認情況下就被瀏覽器攔截,導(dǎo)致無法獲得返回數(shù)據(jù)。

          具體跨域的知識點,可以看我的這篇文章《為什么瀏覽器不能跨域發(fā)送 ajax 請求?》

          JSONP 怎么跨域?

          既然 Ajax 不能發(fā)送跨域請求,那我們不用 Ajax,改用 script 標簽。

          HTML 下的 script 標簽會指向一個腳本地址,這個地址允許跨域,瀏覽器會加載這個腳本然后執(zhí)行。

          除了 script 標簽, link、img 等標簽的請求也是允許跨域的。

          下面以通過用戶 id 獲取用戶信息為例。

          前端實現(xiàn)

          在 script 標簽的 src 上,我們指定好需要服務(wù)器進行填充的回調(diào)函數(shù)名 setUser,并帶上用戶 id。

          <script src="http://b.com:4000/user?id=2&callback=setUser"></script>
          

          上面這種直接這樣寫到 HTML 里不太靈活,我們改寫成下面這樣。

          let user = null;
          function setUser(user) {
            // 保存用戶信息
            window.user = user;
            
            // 輸出到頁面上,看看效果。
            document.body.append(
              JSON.stringify(user);
            );
          }
          function getUserById(id) {
            const script = document.createElement('script');
            script.src = `http://b.com:4000/user?id=${id}&callback=setUser`;
            document.body.appendChild(script);
          }
          document.querySelector('button').onclick = function() {
            getUserById(2);
          }
          

          后端實現(xiàn)

          然后是服務(wù)端的處理,這里我用了 Nodejs 的 Express 框架。

          const app = express();
          // ...
          const map = {
            1: { name: 'fe_watermelon' },
            2: { name: '前端西瓜哥' }
          };
          // 例子:/user?id=2&callback=setUser
          app.get('/user', (req, res, next) => {
            const { id, callback } = req.query;
            res.send(`${callback}(${JSON.stringify(map[id])})`);
          });
          // ...
          

          服務(wù)端從 url 的請求字段中提取出 id ,找到對應(yīng)的用戶信息(通常為 JSON 的形式),配合要填充的回調(diào)函數(shù) setUser,組裝成字符串 setUser({"name":"前端西瓜哥"})

          這個內(nèi)容會作為腳本內(nèi)容返回給前端,前端運行這個腳本后,就會執(zhí)行全局作用域下的 setUser 函數(shù),這個函數(shù)還會拿到用戶信息,將其保存下來。

          演示效果

          結(jié)尾

          JSONP 是一種解決跨域的方案,但一般比較少用到。

          因為 JSONP 并不是標準,也不安全,服務(wù)端代碼沒寫好會有代碼注入的風(fēng)險,且無法防范跨站請求偽造(CSRF)攻擊。

          我們也注意到要兜住返回的數(shù)據(jù),必須定義一個全局的函數(shù),在如今主流的模塊化(變量隔離在各個模塊中不暴露到全局)寫法下有點格格不入。

          我是前端西瓜哥,喜歡寫技術(shù)文章,歡迎關(guān)注我。


          主站蜘蛛池模板: 琪琪see色原网一区二区| 中文字幕一区一区三区| 99久久精品日本一区二区免费| 亚洲一区二区三区成人网站| 亚洲中文字幕丝袜制服一区| 欧洲精品码一区二区三区| 无码人妻一区二区三区在线视频 | 一区二区国产精品| 亚洲国产精品无码第一区二区三区| 综合久久一区二区三区| 日韩十八禁一区二区久久| 风间由美在线亚洲一区| 在线精品视频一区二区| 国产精品揄拍一区二区| 中文字幕在线看视频一区二区三区| 国产AV午夜精品一区二区入口| 国产精品无码一区二区三级 | 国产91久久精品一区二区| 无码人妻一区二区三区免费n鬼沢| 国产av熟女一区二区三区| 亚洲一区日韩高清中文字幕亚洲| 国产MD视频一区二区三区| 日韩一区在线视频| 美女免费视频一区二区| 国产麻豆媒一区一区二区三区| 亚洲综合无码一区二区痴汉| 中文字幕人妻第一区| eeuss鲁片一区二区三区| 欧美日本精品一区二区三区 | 亚洲A∨精品一区二区三区| 国产av夜夜欢一区二区三区| 人妻无码一区二区三区四区| 国产一区二区在线观看麻豆| 精品综合一区二区三区| 午夜无码一区二区三区在线观看| 久久久精品日本一区二区三区| 夜夜添无码试看一区二区三区| 国产亚洲一区二区三区在线| 亚洲国产成人久久综合一区| 精品免费国产一区二区三区 | 无码乱码av天堂一区二区|