有關同源策略詳細介紹,請看 這裏
JSONP是服務器與客戶端跨源通訊的經常使用方法。最大特色就是簡單適用,老式瀏覽器所有支持,服務器改造很是小。
它的基本思想是,網頁經過添加一個<script>
元素,向服務器請求JSON數據,這種作法不受同源政策限制;服務器收到請求後,將數據放在一個指定名字的回調函數裏傳回來。
首先,網頁動態插入<script>
元素,由它向跨源網址發出請求。
例子:javascript
客服端java
function addScriptTag(src) { var script = document.createElement('script'); script.setAttribute("type","text/javascript"); script.src = src; document.body.appendChild(script); } window.onload = function () { addScriptTag('http://localhost:3000/test?callback=foo'); } function foo(data) { console.log('Your public IP address is: ' + data.ip); };
上面代碼經過動態添加<script>
元素,向服務器http://localhost:3000
發出請求。注意,該請求的查詢字符串有一個callback
參數,用來指定回調函數的名字,這對於JSONP是必需的。express
服務器收到這個請求之後,會將數據放在回調函數的參數位置返回。json
JavaScript服務端後端
var express = require('express'); var app = express(); app.get('/test', function (req, res) { var cbFunction = req.query.callback res.send(`${cbFunction}({"ip":"110.110.110.110"})`); //或者不用那麼麻煩直接經過express提供的API /** * res.jsonp({ip:"110.110.110.110"}); */ }); var server = app.listen(3000, function () { var host = server.address().address; var port = server.address().port; console.log('Example app listening at http://%s:%s', host, port); });
上面代碼經過express作的簡單後臺,當請求接口時,後端拿到callback
參數而後將其與要返回的數據組合成字符串的形式返回給客戶端。
因爲<script>
元素請求的腳本,直接做爲代碼運行。這時,只要瀏覽器定義了foo
函數,該函數就會當即調用。做爲參數的JSON數據被視爲JavaScript對象,而不是字符串,所以避免了使用JSON.parse
的步驟。跨域
CORS有兩種請求 :簡單請求(simple request)和非簡單請求(not-so-simple request)只要同時知足如下兩大條件,就屬於簡單請求。瀏覽器
請求方法是如下三種方法之一:服務器
HTTP的頭信息不超出如下幾種字段:app
application/x-www-form-urlencoded
、multipart/form-data
、text/plain
凡是不一樣時知足上面兩個條件,就屬於非簡單請求。
瀏覽器對這兩種請求的處理,是不同的。函數
客戶端
var xhr = new XMLHttpRequest() xhr.open('post','http://localhost:3000/test',true) xhr.onload = function(e){ if(e.currentTarget.status==200){ alert(e.currentTarget.responseText) } } xhr.send()
RequestHeaders請求頭信息
Accept:/*/ Accept-Encoding:gzip, deflate, br Accept-Language:zh-CN,zh;q=0.8 Connection:keep-alive Content-Length:0 Host:localhost:3000 Origin:http://localhost:8020 Referer:http://localhost:8020/ User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36
JavaScript服務端
app.post('/test', function (req, res) { res.set('Access-Control-Allow-Origin','http://localhost:8020') res.send({ name:'tom' }) });
ResponseHeaders
Access-Control-Allow-Origin:http://localhost:8020 Connection:keep-alive Content-Length:14 Content-Type:application/json; charset=utf-8 Date:Mon, 09 Apr 2018 02:09:05 GMT ETag:W/"e-v50e5W1R/vD6VVQyxqDA0eSWedA" X-Powered-By:Express
客戶端
var xhr = new XMLHttpRequest() xhr.open('put','http://localhost:3000/test',true) xhr.setRequestHeader('X-Custom-Header', 'value'); xhr.onload = function(e){ if(e.currentTarget.status==200){ alert(e.currentTarget.responseText) } } xhr.send()
當發送上面的http請求時瀏覽器會先發送一個options類型的http的預檢請求
RequestHeaders請求頭信息
Accept:*/* Accept-Encoding:gzip, deflate, br Accept-Language:zh-CN,zh;q=0.8 Access-Control-Request-Headers:x-custom-header Access-Control-Request-Method:PUT Connection:keep-alive Host:localhost:3000 Origin:http://localhost:8020 Referer:http://localhost:8020/ User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36
JavaScript服務端
//options類型用於CORS非簡單請求的預檢請求 app.options('/test',function(req,res){ res.set('Access-Control-Allow-Origin','http://localhost:8020') //必須設置 res.set('Access-Control-Allow-Methods','PUT') //必須設置 res.set('Access-Control-Allow-Headers','X-Custom-Header') //若是瀏覽器請求包括Access-Control-Request-Headers字段,則Access-Control-Allow-Headers字段是必需的。 res.send({status:200,msg:'預檢成功!'}) })
ResponseHeaders
Access-Control-Allow-Headers:X-Custom-Header Access-Control-Allow-Methods:PUT Access-Control-Allow-Origin:http://localhost:8020 Connection:keep-alive Content-Length:38 Content-Type:application/json; charset=utf-8 Date:Mon, 09 Apr 2018 04:08:40 GMT ETag:W/"26-+1THtR73k4ca8avMcdsJULlJZUs" X-Powered-By:Express
關於客戶端和服務端字段相應說明能夠在 這裏查看
一旦服務器經過了"預檢"請求,之後每次瀏覽器正常的CORS請求,就都跟簡單請求同樣,會有一個Origin
頭信息字段。服務器的迴應,也都會有一個Access-Control-Allow-Origin
頭信息字段。
客戶端
RequestHeaders請求頭信息
Accept:*/* Accept-Encoding:gzip, deflate, br Accept-Language:zh-CN,zh;q=0.8 Connection:keep-alive Content-Length:0 Host:localhost:3000 Origin:http://localhost:8020 Referer:http://localhost:8020/ User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36 X-Custom-Header:value
上面頭信息的Origin
字段是瀏覽器自動添加的。
JavaScript服務端
app.put('/test', function (req, res) { res.set('Access-Control-Allow-Origin','http://localhost:8020') res.send({ name:'tom' }) });
ResponseHeaders
Access-Control-Allow-Origin:http://localhost:8020 Connection:keep-alive Content-Length:14 Content-Type:application/json; charset=utf-8 Date:Mon, 09 Apr 2018 04:08:40 GMT ETag:W/"e-v50e5W1R/vD6VVQyxqDA0eSWedA" X-Powered-By:Express
上面頭信息中,Access-Control-Allow-Origin
字段是每次迴應都一定包含的。