前端跨域策略實踐----cors,jsonp

原文地址: https://github.com/HolyZheng/...

瞭解幾個跨域的方案,而且經過簡單實踐進行體會。javascript

如何實踐?

可是,咱們如何進行實踐呢?在哪發請求?向什麼服務器發請求?很簡單,就在當前網頁,打開控制檯,輸入請求的代碼html

var url = 'http://127.0.0.1:8888/';
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.send();

那麼咱們就能夠以當前頁面url做爲origin,向http://127.0.0.1:8888/ ,發送請求GET請求了。
同時在本地建立一個node服務前端

var http = require('http');

http.createServer(function (request, response) {

    response.writeHead(200, {
      'Content-Type': 'text/plain'
    });

    response.end('request success!!!');
}).listen(8888);

console.log('Server running at http://127.0.0.1:8888/');

這樣咱們就有服務器了,你能夠很輕鬆的跟着這遍文章來實踐了,而後從當前網頁發送get請求到本地服務,理所固然跨域了。java

ps: github網站不行(本文最初再github上編寫),會引起csp錯誤,此錯誤是用於防止內容注入攻擊的,不得不說,大網站安全措施作得就是好,轉戰segmentfault作實踐。

cors_error

1. cors

cors(跨域資源共享 Cross-origin resource sharing),它容許瀏覽器向跨域服務器發出XMLHttpRequest請求,從而克服跨域問題,它須要瀏覽器和服務器的同時支持。node

cors 分爲兩種請求,簡單請求和非簡單請求,關於cors的更詳細介紹,推薦阮一峯老師的 跨域資源共享 CORS 詳解,本文注重實踐。

簡單請求

正如上方的例子即是一個簡單請求git

var url = 'http://127.0.0.1:8888/';
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.send();

如何解決此案例的跨域問題呢?
瀏覽器端,瀏覽器會自動在請求頭中添加 origin 字段,咱們不須要操做。github

Request Headers: 
Origin: https://github.com

服務端,Access-Control-Allow-Origin屬性,咱們須要服務端設置此屬性,指定容許的請求源域名,能夠經過指定爲 *來指定因此域名。後端動起來:json

var http = require('http');

http.createServer(function (request, response) {

    response.writeHead(200, {
      'Content-Type': 'text/plain',
      'Access-Control-Allow-Origin': '*'
    });

    response.end('request success!!!');
}).listen(8888);

console.log('Server running at http://127.0.0.1:8888/');

重啓服務,再嘗試segmentfault

cors_error
此次沒有再報錯了,咱們看看服務器放回了什麼
response
nice!跨域成功!後端

非簡單請求

一樣咱們在控制檯輸入一下代碼進行put(非簡單請求)

var url = 'http://127.0.0.1:8888/';
var xhr = new XMLHttpRequest();
xhr.open('PUT', url, true);
xhr.send();

毫無心外的報錯

error_image

在進行非簡單請求的時候,瀏覽器會先發送一次OPTION請求來「預檢」(preflight)該請求是否被容許,請求頭中會經過Access-Control-Request-MethodAccess-Control-Request-Headers來告訴服務器我須要用到的方法和字段,服務器經過返回的頭部信息中的Access-Control-Allow-OriginAccess-Control-Allow-Method來告訴瀏覽器該跨域請求是否被容許。修改後端代碼:

var http = require('http');

http.createServer(function (request, response) {

    response.writeHead(200, {
      'Content-Type': 'text/plain',
      'Access-Control-Allow-Origin': '*',
      'Access-Control-Allow-Methods': 'GET, POST, PUT'
    });

    response.end('request success!!!');
}).listen(8888);

console.log('Server running at http://127.0.0.1:8888/');

能夠看到瀏覽器會先發送一個預檢

option

當確認容許跨域以後,之後再發送該請求,就會省去預檢處理,之間看成簡單請求來操做。很明顯,修改了後端代碼後,此次的put請求時成功的。這裏就不繼續上圖了。

cors總結

cors(跨域資源共享 Cross-origin resource sharing),它容許瀏覽器向跨域服務器發出XMLHttpRequest請求,從而克服跨域問題,它須要瀏覽器和服務器的同時支持。

  1. 瀏覽器端會自動向請求頭添加origin字段,代表當前請求來源。
  2. 瀏覽器端須要設置響應頭的Access-Control-Allow-MethodsAccess-Control-Allow-HeadersAccess-Control-Allow-Origin等字段,指定容許的方法,頭部,源等信息。
  3. 請求分爲簡單請求和非簡單請求,非簡單請求會先進行一次OPTION方法進行預檢,看是否容許當前跨域請求。

2. jsonp

jsonp的原理就是利用就是利用script標籤沒有跨域限制,能夠經過script標籤的src屬性發送GET請求。咱們繼續嘗試,先把後端有關跨域的設置去掉,並重啓服務

var http = require('http');

http.createServer(function (request, response) {

    response.writeHead(200, {
      'Content-Type': 'text/plain'
    });

    response.end('request success!!!');
}).listen(8888);

console.log('Server running at http://127.0.0.1:8888/');

打開咱們的控制檯輸入一下代碼,利用script標籤進行jsonp請求

var script = document.createElement('script');
script.type = 'text/javascript';
script.src = `http://127.0.0.1:8888/`;
document.head.appendChild(script);

能夠看到,後端正常的返回了

request success !!!

並且該請求爲GET請求

Request URL: http://127.0.0.1:8888/
Request Method: GET
Status Code: 200 OK
Remote Address: 127.0.0.1:8888
Referrer Policy: no-referrer-when-downgrade

可是咱們如今只是成功發送了一個跨域請求,可是咱們不像XMLHttpRequest那樣能夠在res.responseText中拿到數據,經過jsonp咱們該怎麼拿到請求的數據呢?方法就是先後端約定一個callback字段名,來傳遞函數名,前端經過該函數來拿到數據。前端代碼修改成:

var script = document.createElement('script');
script.type = 'text/javascript';
script.src = `http://127.0.0.1:8888/?callback=onBack`;
document.head.appendChild(script);
function onBack (res) {
  console.log(JSON.stringify(res));
  // 請求完後刪除添加到頁面上的script標籤
  var head = document.head
  head.removeChild(script)
}

經過callback字段來傳遞函數名onBack,後端代碼修改成

var http = require('http')
var urlTool = require('url')
// json 數據
var data = {'methods': 'jsonp', 'result': 'success'};

http.createServer(function (request, response) {
    var params = urlTool.parse(request.url, true)
    console.log(params)
    response.writeHead(200, {
      'Content-Type': 'text/plain'
    });
    if (params.query && params.query.callback) {

      // callback(data)
      var str = `${params.query.callback}(${JSON.stringify(data)})`
    }

    response.end(str);
}).listen(8888);

console.log('Server running at http://127.0.0.1:8888/');

重啓後端服務,而且在控制檯輸入代碼,能夠看到結果:

jsonp

咱們拿到了數據,而且經過onBack函數將他輸出到了控制檯上!

總結

  1. jsonp是一種跨域方案,他利用script標籤沒有跨域限制的特色,經過script標籤的的src屬性發送GET請求。
  2. 能夠經過先後端約定一個字段名,好比callback,來傳遞一個函數名,從而使得前端可使用對應的callback函數,拿到數據,處理數據。

jsonp和cors比較

  1. CORS與JSONP的使用目的相同,可是比JSONP更強大。
  2. JSONP只支持GET請求,CORS支持全部類型的HTTP請求。JSONP的優點在於支持老式瀏覽器,以及能夠向不支持CORS的網站請求數據。
同源策略:同源策略限制了一個源(origin)中加載文本或腳本與來自其它源(origin)中資源的交互方式,這是一個用於隔離潛在惡意文件的重要安全機制。若是兩個頁面擁有 相同 的 協議(protocol),端口(若是指定),和 主機,那麼這兩個頁面就屬於同一個源(origin)。
相關文章
相關標籤/搜索