初識"跨域請求"和"同源策略"

本章節小編初識跨域請求和同源策略,分享獲取新知,大家一起進步



一、同源策略

什麼是同源策略

所謂同源是指,域名,協議,端口相同。
所謂“同源策略“,簡單的說就是基於安全考慮,當前域不能訪問其他域的東西。


拓展 什麼是協議,域名,端口?

解釋:假如一個網址是 http://baidu.com:8080?user=name&pwd=password

  • http:// 是協議
  • baidu.com 是域名(注意:前面加上“www”即www.baidu.com不是域名)
  • 8080 是端口
  • user=name&pwd=password 是地址帶的參數
    在這裏插入圖片描述

舉例

如果你有一個服務器A,你所需要的script,css,php文件都在服務器A,你寫的html也在服務器A上,然後運行,出現了效果,如果你想在另一臺電腦上運行你的項目(注意另一臺電腦無論有沒有開啓服務器,效果還是會顯示出來的),只要把你寫在服務器A上的協議,域名,端口以及你的項目名稱複製下來,在另一臺電腦上運行,同樣會出現相同的效果,這就實現了同源。

簡單來說,就是你的協議,域名,端口甚至項目名稱都一樣,不同電腦都能實現同樣的效果。


二、跨域講解

當一個請求url的協議、域名、端口三者之間任意一個與當前頁面url不同即爲跨域

當前頁面URL 被請求的頁面URL 是否跨域 原因
http:// www.test.com http:// www.test.com/index.html 同源(協議、域名、端口)相同
http:// www.test.com https:// www.test.com/index.html 協議不同(http/https)
http:// www.test.com http:// www.baidu.com 跨域(主域名不同baidu/test)
http:// www.test.com http://blog.test.com 子域名不同(www/blog)
http:// www.test.com:8080 http:// www.test.com:8081 端口號不同(8080/8081)

舉例

如果有兩個服務器,服務器A和服務器B,服務器A上存儲了php數據,script,甚至是css這些文件,而你在服務器B上只寫了html,然後你所在的服務器B上動態創建script,css,php數據(使用ajax請求),向服務器A上請求你想要的script,css,php數請求據(使用ajax)這些文件,請求這些文件後,你再在服務器B上運行你的html,雖然你的地址是在服務器B上,但是你還是可以運行效果與在服務器A上運行的效果是一樣的,這樣就是跨域名,跨端口,跨協議,實現了跨域。

簡單來說,就是你請求的文件,只要含有“src”,“href”這些屬性,你就能在其他服務器上,請求你所需要的文件,然後在自己的服務器上運行,就實現了跨域(跨域名,跨端口,跨協議)。


三、跨域請求解決方案

關於跨域請求有很多解決方案,下面舉兩個常見的方案

在這裏插入圖片描述

①通過jsonp跨域

JSONP(JSON with Padding)是JSON的一種“使用模式”,可用於解決主流瀏覽器的跨域數據訪問的問題。

通常爲了減輕web服務器的負載,我們把js、css,img等靜態資源分離到另一臺獨立域名的服務器上,在html頁面中再通過相應的標籤從不同域名下加載靜態資源,而被瀏覽器允許,基於此原理,我們可以通過動態創建script,再請求一個帶參網址實現跨域通信

小結:即是動態創建


(1)原生實現:

 <script>
    var script = document.createElement('script');
    script.type = 'text/javascript';

    // 傳參一個回調函數名給後端,方便後端返回時執行這個在前端定義的回調函數
    script.src = 'http://www.test.com:8080/login?user=admin&callback=handleCallback';
    document.head.appendChild(script);

    // 回調執行函數
    function handleCallback(res) {
        alert(JSON.stringify(res));
    }
 </script>

服務端返回如下(返回時即執行全局函數):

handleCallback({"status": true, "user": "admin"})

(2)jquery ajax:

$.ajax({
    url: 'http://www.test.com:8080/login',
    type: 'get',
    dataType: 'jsonp',  // 請求方式爲jsonp
    jsonpCallback: "handleCallback",    // 自定義回調函數名
    data: {}
});

(3)vue.js:

this.$http.jsonp('http://www.test.com:8080/login', {
    params: {},
    jsonp: 'handleCallback'
}).then((res) => {
    console.log(res); 
})

(4)後端node.js代碼示例:

var querystring = require('querystring');
var http = require('http');
var server = http.createServer();

server.on('request', function(req, res) {
    var params = qs.parse(req.url.split('?')[1]);
    var fn = params.callback;

    // jsonp返回設置
    res.writeHead(200, { 'Content-Type': 'text/javascript' });
    res.write(fn + '(' + JSON.stringify(params) + ')');

    res.end();
});

server.listen('8080');
console.log('Server is running at port 8080...');

jsonp缺點:只能實現get一種請求。


② 跨域資源共享(CORS)

CORS是一個W3C標準,全稱是"跨域資源共享"(Cross-origin resource sharing)。

它允許瀏覽器向跨源服務器,發出XMLHttpRequest請求,從而克服了AJAX只能同源使用的限制。

普通跨域請求:只服務端設置Access-Control-Allow-Origin即可,前端無須設置,若要帶cookie請求:前後端都需要設置。

需注意的是:由於同源策略的限制,所讀取的cookie爲跨域請求接口所在域的cookie,而非當前頁。


前端設置:

  • ①原生ajax
// 前端設置是否帶cookie
xhr.withCredentials = true;

例子

var xhr = new XMLHttpRequest(); // IE8/9需用window.XDomainRequest兼容

// 前端設置是否帶cookie
xhr.withCredentials = true;

xhr.open('post', 'http://www.domain.com:8080/login', true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send('user=admin');

xhr.onreadystatechange = function() {
    if (xhr.readyState == 4 && xhr.status == 200) {
        alert(xhr.responseText);
    }
};
  • ②jQuery ajax
$.ajax({
    ...
   xhrFields: {
       withCredentials: true    // 前端設置是否帶cookie
   },
   crossDomain: true,   // 會讓請求頭中包含跨域的額外信息,但不會含cookie
    ...
});
  • ③vue框架

axios設置:

axios.defaults.withCredentials = true

vue-resource設置:

Vue.http.options.credentials = true

服務端設置

若後端設置成功,前端瀏覽器控制檯則不會出現跨域報錯信息,反之,說明沒設成功。

  • Java後臺:
/*
 * 導入包:import javax.servlet.http.HttpServletResponse;
 * 接口參數中定義:HttpServletResponse response
 */

// 允許跨域訪問的域名:若有端口需寫全(協議+域名+端口),若沒有端口末尾不用加'/'
response.setHeader("Access-Control-Allow-Origin", "http://www.domain.com"); 

// 允許前端帶認證cookie:啓用此項後,上面的域名不能爲'*',必須指定具體的域名,否則瀏覽器會提示
response.setHeader("Access-Control-Allow-Credentials", "true"); 

// 提示OPTIONS預檢時,後端需要設置的兩個常用自定義頭
response.setHeader("Access-Control-Allow-Headers", "Content-Type,X-Requested-With");

The best investment is in yourself
在這裏插入圖片描述

2020.04.26 記錄辰兮的第58篇博客

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章