簡單說說什麼是跨域

發表日期:2019年8月15日css


跨域警告的發生

若是你作了一些先後端分離的項目,因爲此時前端所在的服務地址與後端所在的服務地址不同,你可能會遇到一個請求被瀏覽器攔截了的問題,瀏覽器在檢測到當前頁面發起的請求不屬於當前域就會將其攔截,這是由於瀏覽器的「同源策略」。
html


那麼,什麼是同源策略呢?
同源策略用於限制頁面發起不一樣域(源)的請求,用於提升請求的安全性。
若是兩個頁面的協議、端口、IP地址(域名)都相同的話,那麼這兩個頁面就是同源,也就是同一個域。前端

舉例:
以http://192.168.10.1:8080/index.html爲對照源,
http://192.168.10.1:8080/auth/login.html與它是同源
http://192.168.10.1:8181/index.html與它不是同源,由於端口不同;
http://192.168.10.30:8080/index.html與它不是同源,由於IP地址不同。java




有些人會問,既然域不同就會攔截,爲何我用了xxxCDN的css文件,這個請求沒有被攔截呢?
這裏要提一些並非全部的跨域請求都會被攔截的。
1.一般瀏覽器不會攔截一些跨域資源嵌入的請求。
這種所謂的資源嵌入,就是相似於<img>標籤中的src,<script>中的src,<link>中的href這樣的請求,這樣的請求是直接請求資源嵌入到你的頁面中的。因此你使用某個cdn的css文件不會被攔截。【因此有種方式就是經過這種嵌入的方式來進行解決跨域的問題】
2.一般瀏覽器不會攔截一些跨域寫資源的請求。
這種所謂的跨域寫資源,就是所謂的超連接請求,頁面重定向,非XMLHttpRequest方式的表單提交(普通的form表單提交)等等。
3.一般瀏覽器會攔截跨域讀資源的請求。
XMLHttpRequest提交表單,XMLHttpRequest請求資源,【常見於異步操做】web

除此以外,要再次強調的是,同源策略是瀏覽器的安全策略。因此若是你直接經過postman這些可以不借助瀏覽器來發http請求的軟件來發請求的話,它是不會攔截你的跨域請求的。spring




一個能夠用於測試的例子:
(當我把下面的html文件部署到一個web服務器(tomcat,apache等)中的時候,此時這個網頁處於的域應該是個人本機地址localhost:80,此時我根據上述的三個方面來測試瀏覽器是否攔截。結果是隻有最後一個是被攔截的。【不要不部署就直接打開這個頁面,不然的話它只是一個普通的本地文件,而非網絡文件,此時瀏覽器不會認爲這是一個域】)apache

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8" />
    <title>用於測試跨域</title>

</head>
<body>
    <!-- 跨域資源嵌入,容許 -->
    <img src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1565884598468&di=bb6ccc7a3280b183e4e13c852bc8353c&imgtype=0&src=http%3A%2F%2Fs04.lmbang.com%2FM00%2FCA%2FDE%2FDpgiA1uPAOKAXmJfAADir1hWa-A750.gif" alt="">

    <!-- 跨域資源寫操做,容許 -->
    <a href="http://www.baidu.com">百度</a>

    <form action="http://www.baidu.com" method="post" >
        用戶名:<input type="text" name="username" value="" placeholder="">
        <input type="submit" name="提交" value="提交">
    </form>

    <!-- 跨域資源讀操做,禁止 -->
    <button onclick="senddata()">XMLHttpRequest請求</button>

    <script type="text/javascript">
    var xmlhttp=new XMLHttpRequest();

    function senddata(){
        xmlhttp.open("GET","https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1565884598468&di=bb6ccc7a3280b183e4e13c852bc8353c&imgtype=0&src=http%3A%2F%2Fs04.lmbang.com%2FM00%2FCA%2FDE%2FDpgiA1uPAOKAXmJfAADir1hWa-A750.gif",true);
        xmlhttp.send();
    </script>
</body>
</html>




補充:

爲何瀏覽器會使用同源策略?它想解決什麼問題?
首先,先談一下cookie吧,cookie主要用於存儲一些當前網站的一些數據,在一些舊的web開發中有的還會把用戶登陸信息存儲到cookie中。那麼,從安全的角度來考慮的話,你應該但願你的網站的cookie不能被另一個網站使用(否則cookie中的數據就很是容易被別人竊取了),因此這就引入了域的概念,經過域來限制資源的使用,攔截跨域的資源請求。編程


如何容許跨域




有不少手段來解決跨域,但常見的用於解決跨域調用接口的問題就是CORSjson

CORS

  • 如何容許跨域,一種解決方法就是目的域告訴請求者容許什麼來源域來請求,那麼瀏覽器就會知道B域是否容許A域發起請求。
  • CORS("跨域資源共享"(Cross-origin resource sharing))就是這樣一種解決手段。

CORS使得瀏覽器在向目的域發起請求以前先發起一個OPTIONS方式的請求到目的域獲取目的域的信息,好比獲取目的域容許什麼域來請求的信息。

此時目的域一般須要在響應頭中添加如下信息:

  • Access-Control-Allow-Origin:用來聲明什麼域能夠向當前域發起請求。
  • Access-Control-Allow-Methods:用來聲明能夠向當前域發起什麼類型的請求。
  • Access-Control-Max-Age:用來指定本次OPTIONS請求的有效期,單位爲秒,在此期間不用發出另外一條OPTIONS請求。
  • Access-Control-Allow-Headers:用來容許你附加什麼特殊的請求頭來發起請求。【有些先後端分離項目會把token放到header中,這時候這個請求頭就須要Access-Control-Allow-Headers來聲明瞭】
    【在OPTIONS請求成功後,瀏覽器會把這些信息記錄下來,用來判斷髮往目的域的請求是否須要攔截。若是OPTIONS請求失敗,那麼本來要發起的請求就不會發送。】




但有時候發請求是不會觸發OPTIONS請求的。若是這個請求符合如下條件的話:
1.請求的方式是GET、POST或HEAD。
2.請求頭屬於Accept,Accept-Language,Content-Language,Content-Type ,Viewport-Width。
3.請求頭中Content-Type屬於application/x-www-form-urlencoded、multipart/form-data、text/plain中的一個。

這種請求也被稱爲「簡單請求」。




簡單請求的測試:

下面的例子能夠用於測試簡單和非簡單請求是否會發OPTIONS請求

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8" />
    <title>用於測試簡單請求</title>
</head>
<body>
    <button onclick="senddata()">XMLHttpRequest請求</button>
    <script type="text/javascript">
    var xmlhttp=new XMLHttpRequest();

    function senddata(){
        xmlhttp.open("GET","https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1565884598468&di=bb6ccc7a3280b183e4e13c852bc8353c&imgtype=0&src=http%3A%2F%2Fs04.lmbang.com%2FM00%2FCA%2FDE%2FDpgiA1uPAOKAXmJfAADir1hWa-A750.gif",true);
xmlhttp.send();

        //若是你有一個能夠用來測試的接口,能夠嘗試把這一段註釋了,來測試是否發送OPTIONS請求。
  //       xmlhttp.open("POST","http://localhost:8080/hello",true);
         //下面經過加了一個請求頭,使得這個請求不是一個不發OPTIONS的請求。
        // xmlhttp.setRequestHeader("Content-Type", "application/json")
  //       xmlhttp.send();
    }
    </script>
</body>
</html>




後端的處理

下面基於Spring MVC框架來講明後端如何返回返回CORS響應頭(注:在spring mvc中,你能夠直接使用@CrossOrigin來簡單返回CORS響應頭。)。
前端請求測試代碼:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8" />
    <title>用於測試OPTIONS</title>
</head>
<body>
    <!-- 跨域資源讀操做,禁止 -->
    <button onclick="senddata()">XMLHttpRequest請求</button>

    <script type="text/javascript">
    var xmlhttp=new XMLHttpRequest();

    function senddata(){
        //若是你有一個能夠用來測試的接口,能夠嘗試把這一段註釋了,來測試是否發送OPTIONS請求。
        xmlhttp.open("POST","http://localhost:8080/hello",true);
         //下面經過加了一個請求頭,使得這個請求不是一個不發OPTIONS的請求。
        xmlhttp.setRequestHeader("Content-Type", "application/json")
        xmlhttp.send();
    }
    </script>
</body>
</html>

當咱們沒有部署接口的時候,咱們就能夠看到,頁面是發了一個OPTIONS請求的:

並且,瀏覽器控制檯也提示如下信息:




當咱們部署了接口的時候,咱們先嚐試不返回正規的CORS響應頭。




因爲沒有返回CORS響應頭,因此OPTIONS沒有請求到合適的CORS信息,因此請求就會被攔截,因此就會報下圖的兩個警告。




當咱們在響應中添加CORS響應頭後,咱們能夠看到咱們剛剛設置的CORS響應頭被OPTIONS請求成功了。

並且請求也被髮出去了:




對於不一樣編程語言的如何使用CORS,能夠自查。




補充:

  • 除了正常的,例如經過js來處理跨域的。還有一些沙雕的手法,經過修改瀏覽器來不進行同源策略就是其中一種(治標不治本)。
相關文章
相關標籤/搜索