要快樂,不要跨域……
一晃眼一周就又過去了,一不小心就被葉子同學催稿了,但總算在周三這天發了出去. 葉子同學本周帶大家初步了解了下TS,那本周查查就講講跨域那點事~
跨域,一定是我工作以來碰到最多的問題,每次都要和後台研發扯一會,有時候就很納悶~既然本篇的內容是關於跨域,那必須先解釋一下什麼是跨域了,引用MDN上的解釋:當一個資源從與該資源本身所在的伺服器不同的域或埠請求一個資源時,資源會發起一個跨域 HTTP 請求。其實我覺得解釋的不是很清楚,通俗一點講的就是:我訪問域A,然後域A的代碼中需要請求數據,或者是圖片,然後域A發起請求,這個請求需要去訪問域B下的介面,域A和域B,在協議、域名、埠號中有一樣不一致的,那麼...就會產生跨域!
那什麼是域,什麼又是埠呢?
那就拿百度的域名來說吧,百度www.baidu.com,其實它完整的域名是https://www.baidu.com:80,https是該域名的通信協議,關於通信協議這邊大概講一下,通信協議一般被提起較多的是是七層協議或者是說四層協議.七層協議,一般包括物理層,數據鏈路層,網路層,傳輸層,會話層,表示層,應用層.四層協議只是對其進行了概括,籠統的分為了應用層,傳輸層,網路層,網路介面層.HTTP和HTTPs是歸屬於應用層一類,我們熟知的TCP,UDP是屬於傳輸層協議,TCP是較為安全的傳輸層協議,會通過三次握手(前端同學可以了解一下)建立起會話,這種操作其實是為了避免數據的丟失.
IP則是網路層協議.好了好了.感覺有點跑偏了~又把自己通信專業的老本行拿了出來.
不知道為什麼,查查寫這幾個域名的時候有種看到康師傅和康帥傅的感覺....,傻傻分的清楚了嗎~劃重點~劃重點~同一個域名下不同的文件夾是屬於同一個域名下的哦
我們是一個域名哦
埠號是具有網路功能的應用軟體的標識號,埠號是不固定的,可以受到分配,也可以是其默認的埠號.其中http協議的埠號默認是80,我這邊列舉幾個常見的埠號吧~
443 ===>https
22 ===> SSH安全登錄,文件傳送和埠重定向
21 ===> FTP文本傳輸(常見的FileZilla傳輸文件常用)
23 ===> Telnet不安全的文本傳輸
25 ===> SMTP 簡單郵件傳送協議
以上是通常造成跨域的原因.
好了,講了這麼多周邊知識,要開始切入正題了~
下面我以幾個新手經常遇到的問題開始解析:
1. 當我去請求介面的時候,為什麼在控制台netWork中有數據返回,但是頁面就沒有,而且還報跨域錯誤呢?
首先,跨域限制是瀏覽器行為,是瀏覽器出於安全考慮做的限制.我們在請求數據的時候確實是請求了,而且有返回,但是瀏覽器根據response的header發現和當前頁面不是同源,那麼就其返回的數據限制了.如果是在開發環境,後台介面那邊沒有配置跨域,但是你又非常想獲取到數據,那麼也有解決的方法.
第一種:chrome插件裡面有個CORS,可以簡單粗暴的解決,當然前提是你能科學上網咯~如果不能科學上網的話請採用第二種方式.
第二種:我們可以通過使用chrome命令行啟動參數來改變chrome瀏覽器的設置
window下:找到桌面chrome瀏覽器圖標,右鍵「屬性」 如圖:
在目標後面加上 --disable-web-security --user-data-dir(注意--前面有空格)點擊確定,然後打開瀏覽器出現
如果你是Mac 那就很簡單了,退出瀏覽器,然後輸入命令行:
open -a /Applications/Google Chrome.app --args --disable-web-security --user-data-dir
是不是覺得這種方法簡單粗暴,但是這只是暫時的解決方案,畢竟終極大Boss還是沒KO,那我們繼續....
我們一般發出去的請求會被分為簡單請求和複雜請求(預檢請求)
簡單請求
需要(同時)滿足以下條件:
請求方式為以下其中之一
GETHEADPOST
2 請求頭的集合為以下排列組合
AcceptAccept-LanguageContent-LanguageContent-Type (需要注意額外的限制)DPRDownlinkSave-DataViewport-WidthWidth
3.Content-Type 為以下其中之一
text/plainmultipart/form-dataapplication/x-www-form-urlencoded
我又訪問了一下淘寶網的首頁,隨便找了個介面,雖然這是個請求圖片的請求,但是還是有我們需要看的東西
下面一部分是請求頭,我們可以看到Origin欄位表明該請求來自https://www.taobao.com然後上面一部分是響應頭,在一行中攜帶了響應首部欄位 Access-Control-Allow-Origin,服務端返回了Access-Control-Allow-Origin: * 表明,該資源可以被任意外域訪問。那伺服器端如何設置Access-Control-Allow-Origin: * 呢?
這邊查查也把解決方案貼一下,可以通過Nginx來解決,在nginx.conf中配置
addheader "Access-Control-Allow-Origin" "*";addheader "Access-Control-Allow-Methods" "POST,GET,PUT,DELETE,OPTIONS";addheader "Access-Control-Allow-Headers" "Authorization,Content-Type,Accept,Origin,User-Agent,DNT,Cache-Control,X-Mx-ReqToken,Keep-Alive,X-Requested-With,If-Modified-Since";addheader "Access-Control-Allow-Credentials" "true";
如果想進一步去了解Nginx的,可以去看看文檔
複雜請求(預檢請求)
需要滿足以下(任意一條)條件的:1 請求方式為以下其中之一
PUTDELETECONNECTOPTIONSTRACEPATCH
2 設置了非簡單請求的請求頭欄位
3 Content-Type 為非簡單請求的其他值
下面的例子是一個複雜請求,需要先發送OPTIONS請求,然後根據OPTIONS的返回去發送實際的請求
從第一張圖看出,請求頭的"Content-Type",被設置為"application/xml",不屬於簡單請求之一,而且還人為的設置了欄位"X-PINGOTHER", "pingpong",所以該請求是一個複雜請求,然後我們看到第一張圖的Access-Control-Allow-Methods,也就是後面能夠接受的請求方式可以為POST,GET,OPTIONS其中之一,而我們的請求是POST請求剛好滿足條件,所以實際的請求是被伺服器所允許的.
但是...(為什麼總有那麼多但是),有的請求需要帶身份憑證,這個憑證可以通過 HTTP cookies 和 HTTP 認證信息發送 ,一般來說一些登錄信息需要以HTTP Cookies的形式傳輸.但對於跨域的請求,瀏覽器是不會發送身份憑證信息的,如果需要發送,就需要設置一些參數.
withCredentials = true
這個時候響應頭則會返回
Access-Control-Allow-Credentials: true
如果需要發送身份憑證,那麼伺服器不能設置為Access-Control-Allow-Origin:*這邊又是為什麼呢?首先Access-Control-Allow-Origin為星號時,是允許所有外域訪問的,一旦我們發送帶有身份信息的請求時,容易使身份信息被劫持,是一種不安全的行為.所以需要發送身份憑證的時候需要在伺服器上指定請求Origin的域.
好了,這周就講到這了,還好沒拖稿,啊哈哈!886,下周見~


TAG:WeCode365 |