相信大多數前端開發者在需要與後端進行資料互動時,為了友善快捷,都會選擇<code>JQuery</code>中封裝的<code>AJAX</code>方法,但是有些時候,我們隻需要<code>JQuery</code>的<code>AJAX</code>請求方法,而其他的功能用到的很少,這顯然是沒必要的。
其實,原生<code>JavaScript</code>實作<code>AJAX</code>并不難,這篇文章将會講解如何實作簡單的<code>AJAX</code>,還有跨域請求<code>JSONP</code>!
一、AJAX
AJAX的核心是<code>XMLHttpRequest</code>。
一個完整的<code>AJAX</code>請求一般包括以下步驟:
執行個體化<code>XMLHttpRequest</code>對象
連接配接伺服器
發送請求
接收響應資料
我将<code>AJAX</code>請求封裝成<code>ajax()</code>方法,它接受一個配置對象<code>params</code>。
在上面的代碼中,已經添加具體的注釋,如需了解更多<code>AJAX</code>,可檢視部落客的書籍《 JavaScript半知半解》中的 <code>AJAX</code>章節:AJAX
使用執行個體:
二、JSONP
同源政策
AJAX之是以需要“跨域”,罪魁禍首就是浏覽器的 <code>同源政策</code>。即,一個頁面的AJAX隻能擷取這個頁面相同源或者相同域的資料。 如何叫“同源”或者“同域”呢?——<code>協定、域名、端口号都必須相同</code>。例如:
當跨域請求時,一般都會看到這個錯誤: <code>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.</code>
那如何跨域請求呢?這時,JSONP就登場了!
JSONP(JSON with Padding) 是一種跨域請求方式。主要原理是利用了<code>script </code>标簽可以跨域請求的特性,由其 <code>src</code> 屬性發送請求到伺服器,伺服器傳回 <code>JavaScript </code>代碼,浏覽器接受響應,然後就直接執行了,這和通過 <code>script</code> 标簽引用外部檔案的原理是一樣的。
JSONP由兩部分組成:<code>回調函數</code>和<code>資料</code>,回調函數一般是在浏覽器控制,作為參數發往伺服器端(當然,你也可以固定回調函數的名字,但用戶端和伺服器端的名稱一定要一緻)。當伺服器響應時,伺服器端就會把該函數和資料拼成字元串傳回。
JSONP的請求過程:
請求階段:浏覽器建立一個 <code>script</code> 标簽,并給其<code>src</code> 指派(類似 <code>http://example.com/api/?callback=jsonpCallback</code> )。
發送請求:當給<code>script</code>的<code>src</code>指派時,浏覽器就會發起一個請求。
資料響應:服務端将要傳回的<code>資料</code>作為參數和<code>函數名稱</code>拼接在一起(格式類似”<code>jsonpCallback({name: 'abc'})</code>”)傳回。當浏覽器接收到了響應資料,由于發起請求的是 <code>script</code>,是以相當于直接調用 <code>jsonpCallback</code> 方法,并且傳入了一個參數。
對于<code>JQuery</code>的JSONP請求,這裡就不多講了,之前也寫過一篇文章《JQuery的Ajax請求跨域問題》。
在這裡講解一下用原生<code>JavaScript</code>如何實作。
依舊是<code>ajax()</code>方法裡添加JSONP,後面會将兩者整合在一起,JSONP的配置參數主要多了一個<code>jsonp</code>參數,它就是你的回調函數名。
注意:因為 <code>script</code> 标簽的<code> src</code> 屬性隻在第一次設定的時候起作用,導緻 <code>script</code> 标簽沒法重用,是以每次完成操作之後要移除;
在這裡背景使用PHP處理:
注意:别漏了用函數名與資料拼接傳回。
當然,前面也說過,你可以給定固定回調函數名: