原生JavaScript實現AJAX、JSONP

来源:http://www.cnblogs.com/ybq131/archive/2017/02/07/6374620.html
-Advertisement-
Play Games

原生JavaScript實現AJAX、JSONP 相信大多數前端開發者在需要與後端進行數據交互時,為了方便快捷,都會選擇JQuery中封裝的AJAX方法,但是有些時候,我們只需要JQuery的AJAX請求方法,而其他的功能用到的很少,這顯然是沒必要的。 其實,原生JavaScript實現AJAX並不 ...


 

原生JavaScript實現AJAX、JSONP   相信大多數前端開發者在需要與後端進行數據交互時,為了方便快捷,都會選擇JQuery中封裝的AJAX方法,但是有些時候,我們只需要JQueryAJAX請求方法,而其他的功能用到的很少,這顯然是沒必要的。   其實,原生JavaScript實現AJAX並不難,這篇文章將會講解如何實現簡單的AJAX,還有跨域請求JSONP   一、AJAX   AJAX的核心是XMLHttpRequest   一個完整的AJAX請求一般包括以下步驟:
  • 實例化XMLHttpRequest對象
  • 連接伺服器
  • 發送請求
  • 接收響應數據
  我將AJAX請求封裝成ajax()方法,它接受一個配置對象params    
function ajax(params) {   
  params = params || {};   
  params.data = params.data || {};   
  // 判斷是ajax請求還是jsonp請求
  var json = params.jsonp ? jsonp(params) : json(params);   
  // ajax請求   
  function json(params) {   
    //  請求方式,預設是GET
    params.type = (params.type || 'GET').toUpperCase(); 
    // 避免有特殊字元,必須格式化傳輸數據 
    params.data = formatParams(params.data);   
    var xhr = null;   

    // 實例化XMLHttpRequest對象   
    if(window.XMLHttpRequest) {   
      xhr = new XMLHttpRequest();   
    } else {   
      // IE6及其以下版本   
      xhr = new ActiveXObjcet('Microsoft.XMLHTTP');   
    }; 

    // 監聽事件,只要 readyState 的值變化,就會調用 readystatechange 事件
    xhr.onreadystatechange = function() { 
      //  readyState屬性表示請求/響應過程的當前活動階段,4為完成,已經接收到全部響應數據
      if(xhr.readyState == 4) {   
        var status = xhr.status; 
        //  status:響應的HTTP狀態碼,以2開頭的都是成功
        if(status >= 200 && status < 300) {   
          var response = ''; 
          // 判斷接受數據的內容類型 
          var type = xhr.getResponseHeader('Content-type');   
          if(type.indexOf('xml') !== -1 && xhr.responseXML) {   
            response = xhr.responseXML; //Document對象響應   
          } else if(type === 'application/json') {   
            response = JSON.parse(xhr.responseText); //JSON響應   
          } else {   
            response = xhr.responseText; //字元串響應   
          }; 
          // 成功回調函數 
          params.success && params.success(response);   
       } else {   
          params.error && params.error(status);   
       }   
      };   
    }; 
 
    // 連接和傳輸數據   
    if(params.type == 'GET') {
      // 三個參數:請求方式、請求地址(get方式時,傳輸數據是加在地址後的)、是否非同步請求(同步請求的情況極少);
      xhr.open(params.type, params.url + '?' + params.data, true);   
      xhr.send(null);   
    } else {   
      xhr.open(params.type, params.url, true);   
      //必須,設置提交時的內容類型   
      xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8'); 
      // 傳輸數據 
      xhr.send(params.data);   
    }   
  } 
 
  //格式化參數   
  function formatParams(data) {   
    var arr = [];   
    for(var name in data) { 
      //   encodeURIComponent() :用於對 URI 中的某一部分進行編碼
      arr.push(encodeURIComponent(name) + '=' + encodeURIComponent(data[name]));   
    };   
    // 添加一個隨機數參數,防止緩存   
    arr.push('v=' + random());   
    return arr.join('&');   
  }

  // 獲取隨機數   
  function random() {   
    return Math.floor(Math.random() * 10000 + 500);   
  }
}

 

在上面的代碼中readyState的值表示請求/響應過程的當前活動階段,其值得含義如下:
  • 0:為初始化。尚未調用open()方法。
  • 1:啟動。已經調用open方法,但尚未調用send()方法。
  • 2:發送。已經調用send()方法,但尚未接受到響應。
  • 3:接收。已經接收到部分響應數據。
  • 4:完成。已經接收到全部響應數據,並且可以在客戶端使用
使用實例:
 
ajax({   
  url: 'test.php',   // 請求地址
  type: 'POST',   // 請求類型,預設"GET",還可以是"POST"
  data: {'b': '非同步請求'},   // 傳輸數據
  success: function(res){   // 請求成功的回調函數
    console.log(JSON.parse(res));   
  },
  error: function(error) {}   // 請求失敗的回調函數
});

 

二、JSONP   同源策略   AJAX之所以需要“跨域”,罪魁禍首就是瀏覽器的同源策略。即,一個頁面的AJAX只能獲取這個頁面相同源或者相同域的數據。 如何叫“同源”或者“同域”呢?——協議、功能變數名稱、埠號都必須相同。例如


http://example.com 和 https://example.com 不同,因為協議不同;   
http://localhost:8080 和 http://localhost:1000 不同,因為埠不同;   
http://localhost:8080 和 https://example.com 不同,協議、功能變數名稱、埠號都不同,根本不是一家的。


當跨域請求時,一般都會看到這個錯誤:


XMLHttpRequest cannot load http://ghmagical.com/article/?intro=jsonp%E8%AF%B7%E6%B1%82&v=5520. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access

 

那如何跨域請求呢?這時,JSONP就登場了!   JSONP是JSON with Padding(填充式JSON或參數式JSON)的簡寫,是一種非常常用的跨域請求方式。主要原理是利用了script 標簽可以跨域請求的特性,由其 src 屬性發送請求到伺服器,伺服器返回 JavaScript 代碼,瀏覽器接受響應,然後就直接執行了,這和通過 script 標簽引用外部文件的原理是一樣的。   JSONP由兩部分組成:回調函數數據,回調函數是當響應到來時應該在頁面中調用的函數,回調函數的名字一般在請求中指定。當伺服器響應時,伺服器端就會把該函數和數據拼成字元串返回。 JSONP的請求過程:
  • 請求階段:瀏覽器創建一個 script 標簽,並給其src 賦值(類似 http://example.com/api/?callback=jsonpCallback)。
  • 發送請求:當給scriptsrc賦值時,瀏覽器就會發起一個請求。
  • 數據響應:服務端將要返回的數據作為參數和函數名稱拼接在一起(格式類似”jsonpCallback({name: 'abc'})”)返回。當瀏覽器接收到了響應數據,由於發起請求的是 script,所以相當於直接調用 jsonpCallback 方法,並且傳入了一個參數。
  在這裡講解一下用原生JavaScript如何實現。   依舊是ajax()方法里添加JSONP,後面會將兩者整合在一起,JSONP的配置參數主要多了一個jsonp參數,它就是你的回調函數名。
function ajax(params) {   
  params = params || {};   
  params.data = params.data || {};   
  var json = params.jsonp ? jsonp(params) : json(params);      
  // jsonp請求   
  function jsonp(params) {   
    //創建script標簽並加入到頁面中   
    var callbackName = params.jsonp;   
    var head = document.getElementsByTagName('head')[0];   
    // 設置傳遞給後臺的回調參數名   
    params.data['callback'] = callbackName;   
    var data = formatParams(params.data);   
    var script = document.createElement('script');   
    head.appendChild(script);    
    //創建jsonp回調函數   
    window[callbackName] = function(json) {   
      head.removeChild(script);   
      clearTimeout(script.timer);   
      window[callbackName] = null;   
      params.success && params.success(json);   
    };    
    //發送請求   
    script.src = params.url + '?' + data;    
    //為了得知此次請求是否成功,設置超時處理   
    if(params.time) {   
     script.timer = setTimeout(function() {   
       window[callbackName] = null;   
       head.removeChild(script);   
       params.error && params.error({   
         message: '超時'   
       });   
     }, time);   
    }   
  };    
  //格式化參數   
  function formatParams(data) {   
    var arr = [];   
    for(var name in data) {   
      arr.push(encodeURIComponent(name) + '=' + encodeURIComponent(data[name]));   
    };   

    // 添加一個隨機數,防止緩存   
    arr.push('v=' + random());   
    return arr.join('&');   
  }   

  // 獲取隨機數   
  function random() {   
    return Math.floor(Math.random() * 10000 + 500);   
  } }

 




註意:因為 script 標簽的 src 屬性只在第一次設置的時候起作用,導致 script 標簽沒法重用,所以每次完成操作之後要移除;
使用實例:
 


ajax({   
   url: 'test',    // 請求地址
  jsonp: 'jsonpCallback',  // 採用jsonp請求,且回調函數名為"jsonpCallbak",可以設置為合法的字元串
  data: {'b': '非同步請求'},   // 傳輸數據
  success:function(res){   // 請求成功的回調函數
    console.log(res);   
  },
  error: function(error) {}   // 請求失敗的回調函數
});
  雖然JSONP非常簡單易用,不過,它也存在兩點不足
  •  JSONP是從其他域載入代碼執行,如果其他域不安全,可能會夾帶一些惡意代碼,而此時除了完全放棄JSONP調用之外,沒辦法追究
  • 要確認JSONP請求是否失敗並不容易

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

-Advertisement-
Play Games
更多相關文章
  • 今天,我們來講備忘錄模式 一、案例: 小伙伴們都玩過單機游戲或者說RPG類的游戲吧,我們在打BOSS之前,需要先存一下檔,以免BOSS打不過從頭再來,好,下麵,我們用簡單的控制台應用程式來描述一下這個場景。 客戶端調用: 好了,我們很好的描述了我們案例中的場景,那下麵,我們看一下我們這段代碼有什麼不 ...
  • 什麼是微服務 一些協同工作的小而自治的服務 微服務的優點 技術異構性 彈性 擴展性 簡化部署 對可替代性的優化 微服務的原則 原則舉例 ...
  • Netty 提供非同步的、事件驅動的網路應用程式框架和工具,用以快速開發高性能、高可靠性的網路伺服器和客戶端程式 本文對Netty做了一個總體概覽 ...
  • 今天我們來講一下適配器模式。下麵,我們描述一個場景: 不管是籃球隊還是足球隊,都會有外援的,在隊內訓練與安排戰術的時候,外援可能聽不懂漢語的,那麼,他們怎麼交流呢,這就需要一個翻譯了。其實,這個翻譯就起到了一個適配器的效果。 何為適配器模式:將一個介面轉換成為客戶希望的另外一個介面,使得原本由於介面 ...
  • 閱讀目錄 前言 回顧 本地的一致性 領域事件發佈出現異常 訂閱者處理出現異常 結語 一、前言 上篇中我們初步運用了領域事件,其中還有一些問題我們沒有解決,所以實現是不健壯的,下麵先來回顧一下。 二、回顧 先貼一下上篇中的遺留的問題: 不知道大家有沒有發現這裡代碼上的一個問題,就是DomainEven ...
  • 今天我們來將狀態模式,首先,我們來描述下麵一個場景: 一、案例: 在工作過程中,根據時間段的不同,我們工作的狀態也有所不同,下麵,我們用簡單的控制台應用程式,來實現一下這個場景。 客戶端 二、演繹 1、第一步演繹 看到上面用代碼描述的場景,對於我們學了好多設計模式的小伙伴來講,是不是顯得特別的挫,最 ...
  • 什麼是微服務? 微服務存在多種定義。 如果搜索 Internet,會發現許多有用的資源,這些資源提供了自己的觀點和定義。 但在微服務的以下大部分特性上,已廣泛達成共識: 封裝客戶方案或業務方案。 你要解決什麼問題? 由小型工程團隊開發。 使用任何編程語言編寫並使用任何框架。 由獨立控製版本、部署及縮 ...
  • 1.module.export可以公共方法,也可以公共變數 2. 調用公共方法的時候,寫預設參數的時候可以這樣: function wxReq(method, url, header, data, successCb, failCb, fail, that) {} 調用的時候可以 wxReq("GE ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...