1. 程式人生 > >跨域解決方案二:使用JSONP實現跨域

跨域解決方案二:使用JSONP實現跨域

跨域的實現方式有多種,除了 上篇文章 提到的CORS外,常見的還有JSONP、HTML5、Flash、iframe、xhr2等。

這篇文章對JSONP的跨域原理進行了探索,並將我的心得記錄在這裡和大家分享。

JSONP跨域原理探祕

我們知道,使用 XMLHTTPRequest 物件傳送HTTP請求時,會遇到 同源策略 問題,域不同請求會被瀏覽器攔截。

那麼是否有方法能繞過 XMLHTTPRequest 物件進行HTTP跨域請求呢?

換句話說,不使用 XMLHTTPRequest 物件是否可以傳送跨域HTTP請求呢?

細心的你可能會發現,像諸如:

<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" href="http://www.c.com/assets/css/1.css" />

這種標籤是不會遇到"跨域"問題的,嚴格意義上講,這不是跨域,跨域是指在指令碼程式碼中向非同源域傳送HTTP請求,這只是跨站資源請求。

那麼,我們是否可以利用跨站資源請求這一方式來實現跨域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個片斷中定義了一個處理函式handler(),這個處理函式比較簡單,沒有對資料做任何處理,只是把它alert出來;第2個片斷呼叫了它,執行這個頁面瀏覽器會彈出"success"。

我們假設第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程式碼直接寫在頁面是等效的,但是,我們由此可以聯想到什麼?

我們是否可以事先在本頁面定義處理程式,服務端返回JS指令碼,指令碼的內容就是對處理程式的回撥,服務返回的資料通過引數的形式傳回:

handler('服務返回的資料');

然後通過動態向當前頁面head節點新增<script src="服務地址"></script>節點的方式來“偽造”HTTP請求?

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

先寫服務端,非常簡單的一個服務,返回字串"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;
            }
        }
    }
}

再寫客戶端,一個簡單的靜態Web頁,index.html:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title></title>
    <script type="text/javascript">
        // 跨域傳送HTTP請求,從服務端獲取字串"Hello World" 
        function getHello() {
            var script = document.createElement('script');
            script.setAttribute('src', 'http://localhost:8546/Service.ashx');
            document.querySelector("head").appendChild(script);
        }
        // 處理函式
        function handler(data) {
            alert(data);
            // our code here...
        }
    </script>
</head>
<body>
    <input type="button" value="傳送跨域HTTP請求,獲取Hello World" onclick="getHello()" />
</body>
</html>

測試成功!

在這個測試例子中,我們使用一般處理程式編寫了一個簡單的返回Hello World的服務,然後使用動態建立<script></script>節點的方式實現了跨域HTTP請求。

由於<script>、<img>標籤資源請求是非同步的,所以我們就實現了一個跨域的非同步HTTP請求。

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

不同的請求應該由不同的處理程式來處理,對上面的程式碼稍做修改,只需要給<script>標籤的src屬性中的URL新增一個引數來指定回撥函式的名稱就可以了:

服務端:

        public void ProcessRequest(HttpContext context)
        {
            context.Response.ContentType = "text/plain";

            // 前端指定的回撥函式名稱
            var callbackFuncName = context.Request.QueryString["callback"];
            var responseData = "Hello World";
            // 回撥指令碼,形如: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">
        // 跨域傳送HTTP請求,從服務端獲取字串"Hello World" 
        function getHello() {
            var script = document.createElement('script');
            script.setAttribute('src', 'http://localhost:8546/Service.ashx?callback=handler');//callback指定回撥函式名稱
            document.querySelector("head").appendChild(script);
        }
        // 處理函式
        function handler(data) {
            alert(data);
            // our code here...
        }
    </script>

</head>
<body>
    <input type="button" value="傳送跨域HTTP請求,獲取Hello World" onclick="getHello()" />
</body>
</html>

使用jQuery的JSONP跨域

在上面的章節我們探及了JSONP跨域的原理。幸運的是,我們並不需要每次都寫這麼多程式碼來完成一次跨域請求。

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

<!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",
            url: "http://localhost:8546/Service.ashx",
            dataType: "jsonp",//一定要指明為jsonp
            success: function (data) {
                alert(data);
            },
            error: function () {
                alert('fail');
            }
        });
    </script>
</head>
<body>
    使用jQuery一切將會變得非常簡單。
</body>
</html>

只需要將dataType設定為"jsonp"就可以進行跨域請求了,一切就像傳送非跨域請求那樣簡單。

jQuery為我們封裝好了回撥函式,一般情況下不需要我們單獨去寫,如果你不想在success中處理,想單獨寫處理函式,那麼可以通過設定這2個引數來實現:

  • jsonp: "callback",//傳遞給服務端的回撥函式引數名,如果不設定此項,則預設是"callback"
  • jsonpCallback: "handler",//傳遞給服務端的回撥函式名稱,如果不設定此項,則預設是形如"jQuery111007837897759742043_1460657212499"的由jQuery自動生成的函式名稱,會自動在$.ajax方法的success中完成呼叫。

 

必須要強調的是:

1.JSONP雖然看起來很像一般的ajax請求,但其原理不同,JSONP是對文章第一小節原理的封裝,是通過<script>標籤的動態載入來實現的跨域請求,而一般的ajax請求是通過XMLHttpRequest物件進行;

2.JSONP不是一種標準協議,其安全性和穩定性都不如 W3C 推薦的 CORS

3.JSONP不支援POST請求,即使把請求型別設定為post,其本質上仍然是一個get請求。

JavaScript中的跨域解決方案彙總:

相關推薦

解決方案使用JSONP實現

跨域的實現方式有多種,除了 上篇文章 提到的CORS外,常見的還有JSONP、HTML5、Flash、iframe、xhr2等。 這篇文章對JSONP的跨域原理進行了探索,並將我的心得記錄在這裡和大家分享。 JSONP跨域原理探祕 我們知道,使用 XMLHTTPRequest 物件傳送HTTP請求時,會

解決方案JSONP

同源策略 巴拉巴拉巴拉….(定義就不講了,簡單來說就是協議、埠、域名要相同) 注意:協議和埠引起的不同,不在前端解決的範圍內 JSONP jsonp的原理很簡單,就是動態的創造script標籤,然後利用script的src 不受同源策略約

解決方案使用CORS實現

跨站HTTP請求(Cross-site HTTP request)是指發起請求的資源所在域不同於請求指向的資源所在域的HTTP請求。 比如說,我在Web網站A(www.a.com)中通過<img>標籤引入了B站的資源(www.b.com/images/1.jpg),那麼A站會向B站發起一個跨站請

請求之jsonp詳解

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://w

ASP.NET中JSONP的兩種實現以及其他解決方案的簡單實現 ASP.NET中JSONP的兩種實現以及其他解決方案的簡單實現

ASP.NET中JSONP的兩種實現以及其他跨域解決方案的簡單實現    jQuery中JSONP的兩種實現方式:    都很簡單,所以直接上程式碼!    前臺程式碼如下: &l

【PHP】Ajax解決方案jsonp、cors

code col 服務器 實現 官方 跨域傳輸 ref 響應 非官方 參考文章: 1、https://blog.csdn.net/u014727260/article/details/72793459 (後臺java,實際上差不多) 2、 如何解決ajax跨域傳輸 數據的問

CORS ———— 解決方案

其他跨域方案請看: 以下介紹CORS跨域解決方案 一、什麼是CORS? CORS (Corss-Orign Resource Sharing) 是W3C工作草案,是一份瀏覽器技術的規範。定義了跨域資源訪問時,瀏覽器和伺服器之間如何通訊,使用自定義的http頭部允

解決方案JSONP

什麼是跨域 老生常談的問題了。下面列出一個表格: 牢記:只要協議schema ,域名,子域名,埠有一個不同的都是跨域! 而且跨域問題上,域僅僅是通過URL的首部來識別的,而不會去嘗試判斷兩個域是否在同一個IP上(這涉及到DNS解析) 下面介紹

Ajax通過jsonp實現訪問,訪問成功但走error不走success的的問題解決

前提 最近工作中有個需求就是JS實現跨域訪問,眾所周知JS不能實現跨域訪問,但是”script”標籤卻可以,這是Jsonp實現的原理,這裡就不多講了,這裡主要講ajax通過Jsonp跨域訪問雖然返回200但總是走error不走success的解決方案

解決方案等一些問題(jsonp,nginx代理等)

1. 用jsonp跨域需要後臺修改程式碼後臺需要用前臺傳遞的函式名將資料包起來,本質上是一個函式呼叫,將資料當做引數傳遞回來。callback({"data": "ok"})所以普通的ajax請求產生的資料不能用jsonp去請求;但是一個介面也可以同時支援普通的ajax請求(

利用jsonp實現請求

get p地址 doc ajax請求 -s tar 原理 安全策略 都是   同源策略,它是由Netscape提出的一個著名的安全策略。現在所有支持JavaScript 的瀏覽器都會使用這個策略。所謂同源是指,域名,協議,端口相同。當一個瀏覽器的兩個tab頁中分別打開來 百

JSON解決方案收集

get ogl obb 本地 allow con mesa 跨域請求 loader 最近面試問的挺多的一個問題,就是JavaScript的跨域問題。在這裏,對跨域的一些方法做個總結。由於瀏覽器的同源策略,不同域名、不同端口、不同協議都會構成跨域;但在實際的業務中,很多

前端如何去做解決方案

時也 for 前後端 define 影響 list nts 告訴 iframe 前言 那些你,你常用的跨域解決方案除了jsonp 之外,還有其他的嗎?今日早讀文章可以告訴你,本文由 金蝶 @scq000授權分享。 正文從這開始~ 瀏覽器在請求不同域的資源時,會因為同源策略的

實戰案例構建docker容器集群 (解決方案使用自定義網橋連接主機容器)

docker一、實驗環境虛擬機a兩塊網卡 eth0 eth1 (IP地址static或者dhcp)虛擬機b兩塊網卡 eth0 eth1 (IP地址static或者dhcp)二、在兩臺虛擬機上配置網橋虛擬機a操作:apt-get install bridge-utilsvim /etc/ne

前端常見解決方案(全)

-type crm api war str bsp 斷開 jquery 數據塊 什麽是跨域? 跨域是指一個域下的文檔或腳本試圖去請求另一個域下的資源,這裏跨域是廣義的。 廣義的跨域: 1.) 資源跳轉: A鏈接、重定向、表單提交 2.) 資源嵌入: <link

前端常見解決方案

自定義 兩個 ech cors onload 消息 strong put 普通 什麽是跨域? 跨域是指一個域下的文檔或腳本試圖去請求另一個域下的資源,這裏跨域是廣義的。 廣義的跨域: 1.) 資源跳轉: A鏈接、重定向、表單提交 2.) 資源嵌入:<lin

方案優化網站實現掃描維碼關註微信公眾號,自動登陸網站並獲取其信息

用戶 class his onerror 就會 openid display 要點 rac 上一篇 《網站實現掃描二維碼關註微信公眾號,自動登陸網站並獲取其信息》 中已經實現用戶掃碼登陸網站並獲取其信息 但是上一篇方案中存在一個問題,也就是文章末尾指出的可以優化的地方(可

jsonp實現

oct 屬性 ron 解析 js文件 pos 一個 spa lan 原理:利用了src屬性都可實現跨域的特點,創建新的script標簽,src的值為要進行跨域訪問的地址,這樣就可以執行不同域的js代碼了,這裏在src進行賦值的時候傳一個callback的函數名到服務器,服

spring mvc的解決方案

增加 是否 strac inf oss ref nds sso option 什麽是跨域 一句話:同一個ip、同一個網絡協議、同一個端口,三者都滿足就是同一個域,否則就是跨域。 為什麽非得跨域 基於兩個方面: a. web應用本身是部署在不同的服務器上 b.基於開發的角度

Jsonp實現訪問

turn latest dumps 填充 -c meta index itl add 同源策略 同源策略(Same origin policy)是一種約定,它是瀏覽器最核心也最基本的安全功能,如果缺少了同源策略,則瀏覽器的正常功能可能都會受到影響。可以說Web是構建在同源