title: 樂優(yōu)商城學(xué)習(xí)筆記三
date: 2019-04-13 09:59:32
tags:
- 樂優(yōu)商城
- java
- springboot
categories:
- 樂優(yōu)商城
利用cors解決跨域問題
1.跨域問題
跨域:瀏覽器對于javascript的同源策略的限制 。
以下情況都屬于跨域:
跨域原因說明 | 示例 |
---|---|
域名不同 |
www.jd.com 與 www.taobao.com
|
域名相同掏愁,端口不同 |
www.jd.com:8080 與 www.jd.com:8081
|
二級域名不同 |
item.jd.com 與 miaosha.jd.com
|
如果域名和端口都相同,但是請求路徑不同尤蛮,不屬于跨域,如:
www.jd.com/item
www.jd.com/goods
而我們剛才是從manage.leyou.com
去訪問api.leyou.com
菠镇,這屬于二級域名不同芳撒,跨域了。
2.為什么有跨域問題浓冒?
跨域不一定會有跨域問題。
因為跨域問題是瀏覽器對于ajax請求的一種安全限制:一個頁面發(fā)起的ajax請求尖坤,只能是與當(dāng)前頁域名相同的路徑稳懒,這能有效的阻止跨站攻擊。
因此:跨域問題 是針對ajax的一種限制慢味。
但是這卻給我們的開發(fā)帶來了不便场梆,而且在實際生產(chǎn)環(huán)境中,肯定會有很多臺服務(wù)器之間交互纯路,地址和端口都可能不同或油,怎么辦?
3.解決跨域問題的方案
目前比較常用的跨域解決方案有3種:
-
Jsonp
最早的解決方案驰唬,利用script標(biāo)簽可以跨域的原理實現(xiàn)顶岸。
限制:
- 需要服務(wù)的支持
- 只能發(fā)起GET請求
-
nginx反向代理
思路是:利用nginx把跨域反向代理為不跨域腔彰,支持各種請求方式
缺點:需要在nginx進(jìn)行額外配置,語義不清晰
-
CORS
規(guī)范化的跨域請求解決方案蜕琴,安全可靠萍桌。
優(yōu)勢:
- 在服務(wù)端進(jìn)行控制是否允許跨域,可自定義規(guī)則
- 支持各種請求方式
缺點:
- 會產(chǎn)生額外的請求
我們這里會采用cors的跨域方案凌简。
4.cors解決跨域
4.1.什么是cors
CORS是一個W3C標(biāo)準(zhǔn),全稱是"跨域資源共享"(Cross-origin resource sharing)恃逻。
它允許瀏覽器向跨源服務(wù)器雏搂,發(fā)出XMLHttpRequest
請求,從而克服了AJAX只能同源使用的限制寇损。
CORS需要瀏覽器和服務(wù)器同時支持凸郑。目前,所有瀏覽器都支持該功能矛市,IE瀏覽器不能低于IE10芙沥。
-
瀏覽器端:
目前,所有瀏覽器都支持該功能(IE10以下不行)浊吏。整個CORS通信過程而昨,都是瀏覽器自動完成,不需要用戶參與找田。
-
服務(wù)端:
CORS通信與AJAX沒有任何差別歌憨,因此你不需要改變以前的業(yè)務(wù)邏輯。只不過墩衙,瀏覽器會在請求中攜帶一些頭信息务嫡,我們需要以此判斷是否允許其跨域,然后在響應(yīng)頭中加入一些信息即可漆改。這一般通過過濾器完成即可心铃。
4.2.原理有點復(fù)雜
瀏覽器會將ajax請求分為兩類,其處理方案略有差異:簡單請求挫剑、特殊請求去扣。
4.2.1.簡單請求
只要同時滿足以下兩大條件,就屬于簡單請求暮顺。:
(1) 請求方法是以下三種方法之一:
- HEAD
- GET
- POST
(2)HTTP的頭信息不超出以下幾種字段:
- Accept
- Accept-Language
- Content-Language
- Last-Event-ID
- Content-Type:只限于三個值
application/x-www-form-urlencoded
厅篓、multipart/form-data
、text/plain
如果服務(wù)器允許跨域捶码,需要在返回的響應(yīng)頭中攜帶下面信息:
Access-Control-Allow-Origin: http://manage.leyou.com
Access-Control-Allow-Credentials: true
Content-Type: text/html; charset=utf-8
- Access-Control-Allow-Origin:可接受的域羽氮,是一個具體域名或者*(代表任意域名)
- Access-Control-Allow-Credentials:是否允許攜帶cookie,默認(rèn)情況下惫恼,cors不會攜帶cookie档押,除非這個值是true
有關(guān)cookie:
要想操作cookie,需要滿足3個條件:
- 服務(wù)的響應(yīng)頭中需要攜帶Access-Control-Allow-Credentials并且為true。
- 瀏覽器發(fā)起ajax需要指定withCredentials 為true
- 響應(yīng)頭中的Access-Control-Allow-Origin一定不能為*令宿,必須是指定的域名
4.2.2.特殊請求
不符合簡單請求的條件叼耙,會被瀏覽器判定為特殊請求,,例如請求方式為PUT粒没。
預(yù)檢請求
特殊請求會在正式通信之前筛婉,增加一次HTTP查詢請求,稱為"預(yù)檢"請求(preflight)癞松。
瀏覽器先詢問服務(wù)器爽撒,當(dāng)前網(wǎng)頁所在的域名是否在服務(wù)器的許可名單之中,以及可以使用哪些HTTP動詞和頭信息字段响蓉。只有得到肯定答復(fù)硕勿,瀏覽器才會發(fā)出正式的XMLHttpRequest
請求,否則就報錯枫甲。
一個“預(yù)檢”請求的樣板:
OPTIONS /cors HTTP/1.1
Origin: http://manage.leyou.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
Host: api.leyou.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
與簡單請求相比源武,除了Origin以外,多了兩個頭:
- Access-Control-Request-Method:接下來會用到的請求方式想幻,比如PUT
- Access-Control-Request-Headers:會額外用到的頭信息
預(yù)檢請求的響應(yīng)
服務(wù)的收到預(yù)檢請求粱栖,如果許可跨域,會發(fā)出響應(yīng):
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://manage.leyou.com
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Access-Control-Max-Age: 1728000
Content-Type: text/html; charset=utf-8
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain
除了Access-Control-Allow-Origin
和Access-Control-Allow-Credentials
以外举畸,這里又額外多出3個頭:
- Access-Control-Allow-Methods:允許訪問的方式
- Access-Control-Allow-Headers:允許攜帶的頭
- Access-Control-Max-Age:本次許可的有效時長查排,單位是秒,過期之前的ajax請求就無需再次進(jìn)行預(yù)檢了
如果瀏覽器得到上述響應(yīng)抄沮,則認(rèn)定為可以跨域跋核,后續(xù)就跟簡單請求的處理是一樣的了。
5. CORS跨域?qū)崿F(xiàn)
SpringMVC已經(jīng)幫我們寫好了CORS的跨域過濾器:CorsFilter ,內(nèi)部已經(jīng)實現(xiàn)了剛才所講的判定邏輯叛买,我們直接用就好了砂代。
package cn.smallmartial.gateway.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
/**
* @Author smallmartial
* @Date 2019/4/13
* @Email smallmarital@qq.com
*/
@Configuration
public class GlobalCorsConfig {
@Bean
public CorsFilter corsFilter() {
//1.添加CORS配置信息
CorsConfiguration config = new CorsConfiguration();
//1) 允許的域,不要寫*,否則cookie就無法使用了
config.addAllowedOrigin("http://manage.leyou.com");
//2) 是否發(fā)送Cookie信息
config.setAllowCredentials(true);
//3) 允許的請求方式
config.addAllowedMethod("OPTIONS");
config.addAllowedMethod("HEAD");
config.addAllowedMethod("GET");
config.addAllowedMethod("PUT");
config.addAllowedMethod("POST");
config.addAllowedMethod("DELETE");
config.addAllowedMethod("PATCH");
// 4)允許的頭信息
config.addAllowedHeader("*");
//5)有效時長
config.setMaxAge(3600L);
//2.添加映射路徑率挣,我們攔截一切請求
UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
configSource.registerCorsConfiguration("/**", config);
//3.返回新的CorsFilter.
return new CorsFilter(configSource);
}
}