Spring Cloud第二代網關GateWay是由純Netty開發,底層爲Reactor,WebFlux構建,不依賴任何Servlet容器,它不一樣於Zuul,使用的是異步IO,性能較Zuul提高1.6倍。搭建過程以下(本次搭建的爲子項目,主項目能夠參考Nacos搭建流程 )java
pomweb
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency>
配置文件正則表達式
server: port: 8040 spring: application: name: gateway cloud: nacos: discovery: server-addr: 127.0.0.1:8848 gateway: discovery: locator: enabled: true
以上的意思不只是把本身給註冊到nacos,而且獲取nacos的全部註冊服務。redis
啓動網關項目,如今就能夠進行網絡路由了。訪問格式爲 ip:端口/服務註冊名/restfulapi-urlspring
比方說咱們如今有兩個微服務項目,一個爲user(端口8082),一個爲nacos(端口8081).編程
三大核心概念後端
因爲咱們使用了nacos來進行服務發現,因此咱們使用了以前的配置文件,但若是不使用服務發現,只作常規的轉發以下api
spring: cloud: gateway: routes: - id: some_route uri: http://www.baidu.com predicates: - Path=/user/1 filtes: - AddRequestHeader=X-Request-Foo, Bar
這段配置的意思是說,當咱們請求/user/1的url的時候,會添加AddRequestHeader=X-Request-Foo, Bar過濾器作一些處理,而後路由到http://www.baidu.com。跨域
路由謂詞配置工廠瀏覽器
路由謂詞配置工廠由一整套謂詞來進行配置轉發的不一樣狀況。
謂詞工廠 | 備註 |
---|---|
After | 此謂詞匹配當前日期時間以後發生的請求。 |
Before | 此謂詞匹配在當前日期時間以前發生的請求。 |
Between | 此謂詞匹配datetime1以後和datetime2以前發生的請求。 datetime2參數必須在datetime1以後。 |
Cookie | Cookie Route Predicate Factory有兩個參數,cookie名稱和正則表達式。此謂詞匹配具備給定名稱且值與正則表達式匹配的cookie。 |
Header | Header Route Predicate Factory有兩個參數,標題名稱和正則表達式。與具備給定名稱且值與正則表達式匹配的標頭匹配。 |
Host | Host Route Predicate Factory採用一個參數:主機名模式。該模式是一種Ant樣式模式「.」做爲分隔符。此謂詞匹配與模式匹配的Host標頭。 |
Method | Method Route Predicate Factory採用一個參數:要匹配的HTTP方法。 |
Path | 匹配請求的path |
Query | Query Route Predicate Factory有兩個參數:一個必需的參數和一個可選的正則表達式。 |
RemoteAddr | RemoteAddr Route Predicate Factory採用CIDR符號(IPv4或IPv6)字符串的列表(最小值爲1),例如, 192.168.0.1/16(其中192.168.0.1是IP地址,16是子網掩碼)。 |
路由到指定URL
如今咱們去掉nacos的配置,不禁nacos來發現
spring: application: name: gateway cloud: gateway: routes: - id: gate uri: http://127.0.0.1:8082 predicates: #由/user來匹配跳轉 - Path=/user/** filters: #跳轉後省略第一個通配 - StripPrefix=1
此時訪問
將跳轉到
spring: application: name: gateway cloud: gateway: routes: - id: gate uri: http://127.0.0.1:8082 predicates: #由/user來匹配跳轉 - Path=/user/** #在2019-12-14日20:26後容許該轉發 - After=2019-12-14T20:26:15.667+08:00[Asia/Shanghai] filters: #跳轉後省略第一個通配 - StripPrefix=1
這裏表示在該時間後容許轉發,若是咱們將該時間設置爲
spring: application: name: gateway cloud: gateway: routes: - id: gate uri: http://127.0.0.1:8082 predicates: #由/user來匹配跳轉 - Path=/user/** #在2019-12-15日20:26後容許該轉發 - After=2019-12-15T20:26:15.667+08:00[Asia/Shanghai] filters: #跳轉後省略第一個通配 - StripPrefix=1
則轉發失敗,返回404
咱們能夠經過如下方法來獲取這裏的時間設置
public class TimeTest { public static void main(String[] args) { System.out.println(ZonedDateTime.now()); } }
運行結果
2019-12-14T20:43:34.755+08:00[Asia/Shanghai]
如今咱們將上面的15號改成Before
spring: application: name: gateway cloud: gateway: routes: - id: gate uri: http://127.0.0.1:8082 predicates: #由/user來匹配跳轉 - Path=/user/** #在2019-12-15日20:26前容許該轉發 - Before=2019-12-15T20:26:15.667+08:00[Asia/Shanghai] filters: #跳轉後省略第一個通配 - StripPrefix=1
此時就能夠正常轉發,而改爲14號則會失敗。
spring: application: name: gateway cloud: gateway: routes: - id: gate uri: http://127.0.0.1:8082 predicates: #由/user來匹配跳轉 - Path=/user/** #在2019-12-14日20:26到2019-12-15日20:26之間容許該轉發 - Between=2019-12-14T20:26:15.667+08:00[Asia/Shanghai],2019-12-15T20:26:15.667+08:00[Asia/Shanghai] filters: #跳轉後省略第一個通配 - StripPrefix=1
咱們在user模塊增長一個帶cookie的Controller
@Slf4j @RestController public class CookieController { @GetMapping("/welcome") public Boolean handle(HttpServletRequest request, HttpServletResponse response) throws Exception { Cookie cookie = new Cookie("test","value"); cookie.setMaxAge(Integer.MAX_VALUE); response.addCookie(cookie); log.info("welcome"); return true; } }
此時咱們訪問該Controller爲
此時網關這邊配置爲
spring: application: name: gateway cloud: gateway: routes: - id: gate uri: http://127.0.0.1:8082 predicates: #由/user來匹配跳轉 - Path=/user/** #只有帶上Cookie名爲test,而且值符合正則value的cookie時,才容許被轉發 - Cookie=test,value filters: #跳轉後省略第一個通配 - StripPrefix=1
如今咱們給user模塊添加一個Controller的方法
@GetMapping("/header") public String header(@RequestHeader("item") String item) { return item; }
咱們經過postman給該方法的訪問添加請求頭
在網關中的配置爲
spring: application: name: gateway cloud: gateway: routes: - id: gate uri: http://127.0.0.1:8082 predicates: #由/user來匹配跳轉 - Path=/user/** #只有帶上請求頭名爲item,而且值符合正則123.p,纔會轉發 - Header=item,123.p filters: #跳轉後省略第一個通配 - StripPrefix=1
這裏正則.能夠匹配一個單字符
若是咱們在請求頭item中設置錯誤的字符則沒法轉發
要配置Host,咱們須要給服務器的hosts文件添加一個域名映射,固然在互聯網上須要一個域名來作DNS解析。
我這裏給本身的域名添加爲local.register.com
訪問user的find方法
給網關添加配置
spring: application: name: gateway cloud: gateway: routes: - id: gate uri: http://127.0.0.1:8082 predicates: #由/user來匹配跳轉 - Path=/user/** #只有帶上請求頭Host,且值匹配**.register.com:8040才能經過轉發 - Host=**.register.com:8040 filters: #跳轉後省略第一個通配 - StripPrefix=1
此時咱們經過網關訪問以下
spring: application: name: gateway cloud: gateway: routes: - id: gate uri: http://127.0.0.1:8082 predicates: #由/user來匹配跳轉 - Path=/user/** #只有當HTTP請求方法是GET時才能轉發 - Method=GET filters: #跳轉後省略第一個通配 - StripPrefix=1
如今咱們給user模塊增長一個Controller方法
@GetMapping("/query") public String query(@RequestParam("name") String name) { return name; }
訪問以下
網關配置以下
spring: application: name: gateway cloud: gateway: routes: - id: gate uri: http://127.0.0.1:8082 predicates: #由/user來匹配跳轉 - Path=/user/** #只有當請求帶上參數名稱爲name時才能經過轉發 - Query=name filters: #跳轉後省略第一個通配 - StripPrefix=1
若是不帶上該參數則沒法轉發,如
spring: application: name: gateway cloud: gateway: routes: - id: gate uri: http://127.0.0.1:8082 predicates: #由/user來匹配跳轉 - Path=/user/** #只有當請求爲192.168.20.1/24網段(IP地址從192.168.20.1到192.168.20.254)纔會轉發 - RemoteAddr=192.168.20.1/24 filters: #跳轉後省略第一個通配 - StripPrefix=1
例如
可是使用127.0.0.1卻沒法訪問
如今咱們恢復nacos的服務發現
spring: application: name: gateway cloud: nacos: discovery: server-addr: 127.0.0.1:8848 gateway: routes: - id: gate uri: lb://user predicates: #由/user-center來匹配跳轉 - Path=/user-center/** filters: #跳轉後省略第一個通配 - StripPrefix=1
爲了跟不作任何配置相區別,咱們這裏謂詞Path寫了user-center
自定義路由謂詞工廠
假設如今咱們的一個API只有在上午9點到下午5點容許轉發
配置的文件以下
spring: application: name: gateway cloud: nacos: discovery: server-addr: 127.0.0.1:8848 gateway: routes: - id: gate uri: lb://user predicates: #由/user-center來匹配跳轉 - Path=/user-center/** - TimeBetween=上午9:00,下午5:00 filters: #跳轉後省略第一個通配 - StripPrefix=1
因爲這個TimeBetween並非gateway默認的謂詞工廠,因此咱們須要本身來實現一個謂詞工廠,咱們先定義一個時間的配置類
@Data public class TimeBetweenConfig { private LocalTime start; private LocalTime end; }
而後自定義一個謂詞工廠類,該工廠類名稱必須以自定義謂詞開頭(這裏是TimeBetween),以RoutePredicateFactory結尾,並繼承AbstractRoutePredicateFactory抽象類
@Component public class TimeBetweenRoutePredicateFactory extends AbstractRoutePredicateFactory<TimeBetweenConfig>{ public TimeBetweenRoutePredicateFactory() { super(TimeBetweenConfig.class); } @Override public Predicate<ServerWebExchange> apply(TimeBetweenConfig config) { LocalTime start = config.getStart(); LocalTime end = config.getEnd(); return exchange -> { LocalTime now = LocalTime.now(); return now.isAfter(start) && now.isBefore(end); }; } @Override public List<String> shortcutFieldOrder() { return Arrays.asList("start","end"); } }
內置過濾器工廠
1 AddRequestHeader GatewayFilter Factory
2 AddRequestParameter GatewayFilter Factory
3 AddResponseHeader GatewayFilter Factory
4 DedupeResponseHeader GatewayFilter Factory
5 Hystrix GatewayFilter Factory
6 FallbackHeaders GatewayFilter Factory
7 PrefixPath GatewayFilter Factory
8 PreserveHostHeader GatewayFilter Factory
9 RequestRateLimiter GatewayFilter Factory
10 RedirectTo GatewayFilter Factory
11 RemoveHopByHopHeadersFilter GatewayFilter Factory
12 RemoveRequestHeader GatewayFilter Factory
13 RemoveResponseHeader GatewayFilter Factory
14 RewritePath GatewayFilter Factory
15 RewriteResponseHeader GatewayFilter Factory
16 SaveSession GatewayFilter Factory
17 SecureHeaders GatewayFilter Factory
18 SetPath GatewayFilter Factory
19 SetResponseHeader GatewayFilter Factory
20 SetStatus GatewayFilter Factory
21 StripPrefix GatewayFilter Factory
22 Retry GatewayFilter Factory
23 RequestSize GatewayFilter Factory
24 Modify Request Body GatewayFilter Factory
25 Modify Response Body GatewayFilter Factory
26 Default Filters
spring: application: name: gateway cloud: nacos: discovery: server-addr: 192.168.10.172:8848 gateway: routes: - id: gate uri: lb://user predicates: #由/user-center來匹配跳轉 - Path=/user-center/** filters: #跳轉後省略第一個通配 - StripPrefix=1 #增長一個名稱爲X-Request-Foo,值爲Bar的請求頭 - AddRequestHeader=X-Request-Foo,Bar
這裏須要注意的是新增的這個請求頭是轉發之後添加進去的,因此咱們請求網關的時候在瀏覽器中是找不到的,咱們可使用command+N(Windows中idea爲Ctrl+N)來查找NettyRoutingFilter類,而且在filter方法中設置斷點,由如下圖中能夠看到它是被添加進去了。
因爲在user模塊中有這麼一個方法
@GetMapping("/query") public String query(@RequestParam("name") String name) { return name; }
因此咱們在網關配置時
spring: application: name: gateway cloud: nacos: discovery: server-addr: 127.0.0.1:8848 gateway: routes: - id: gate uri: lb://user predicates: #由/user-center來匹配跳轉 - Path=/user-center/** filters: #跳轉後省略第一個通配 - StripPrefix=1 #增長一個名稱爲name,值爲locky的請求參數 - AddRequestParameter=name,locky
因此咱們在網關中請求就能夠不寫參數,直接訪問
spring: application: name: gateway cloud: nacos: discovery: server-addr: 127.0.0.1:8848 gateway: routes: - id: gate uri: lb://user predicates: #由/user-center來匹配跳轉 - Path=/user-center/** filters: #跳轉後省略第一個通配 - StripPrefix=1 #增長一個名稱爲X-Response-Foo,值爲Bar的響應頭 - AddResponseHeader=X-Response-Foo, Bar
Spring Cloud Greenwich SR2提供的新特性,低於這個版本沒法使用。
它的主要做用是去重,例如
spring: application: name: gateway cloud: nacos: discovery: server-addr: 127.0.0.1:8848 gateway: routes: - id: gate uri: lb://user predicates: #由/user-center來匹配跳轉 - Path=/user-center/** - Cookie=test,value filters: #跳轉後省略第一個通配 - StripPrefix=1 #在Http響應報文頭中進行去重,去重目標爲跨域請求 - DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin
Hystrix是Spring Cloud第一代中的容錯組件,不過已經進入維護模式。將來,Hystrix會被Spring Cloud移除掉,取而代之的是Alibaba Sentinel/Resilience4J。
此處不作具體設置了
也是對Hystrix的支持,不作具體設置了
爲匹配的路由添加前綴,咱們在user模塊的find添加一層訪問路徑
@GetMapping("/test/find") @SuppressWarnings("unchecked") public Result<User> findStr() { log.info("訪問成功"); return Result.success(new User(1,"張三",23)); }
網關配置
spring: application: name: gateway cloud: nacos: discovery: server-addr: 127.0.0.1:8848 gateway: routes: - id: gate uri: lb://user predicates: #由/user-center來匹配跳轉 - Path=/user-center/** filters: #跳轉後省略第一個通配 - StripPrefix=1 #跳轉後添加前綴/test - PrefixPath=/test
則
與
一致。
若是不設置,那麼名爲 Host
的Header由Http Client控制;若是設置了,那麼會設置一個請求屬性(preserveHostHeader=true),路由過濾器會檢查從而去判斷是否要發送原始的、名爲Host的Header。這裏主要是經過網關是否向代理服務器轉發請求頭中的Host屬性。
spring: application: name: gateway cloud: nacos: discovery: server-addr: 127.0.0.1:8848 gateway: routes: - id: gate uri: lb://user predicates: #由/user-center來匹配跳轉 - Path=/user-center/** filters: #跳轉後省略第一個通配 - StripPrefix=1 #轉發客戶端的請求報文頭Host給後端代理服務器 - PreserveHostHeader
Gateway自帶的限流服務,但後續咱們會整合Gateway和Sentinel來進行限流和熔斷。
轉發到後端服務後再重定向到一個url.
spring: application: name: gateway cloud: nacos: discovery: server-addr: 127.0.0.1:8848 gateway: routes: - id: gate uri: lb://user predicates: #由/user-center來匹配跳轉 - Path=/user-center/** filters: #跳轉後省略第一個通配 - StripPrefix=1 #轉發到Path,而且攜帶一個http://www.baidu.com到Location的響應頭 - RedirectTo=302,http://www.baidu.com
從以上圖中能夠看出,其實咱們請求的是http://127.0.0.1:8040/user-center/find,可是被重定向到了百度。這裏HTTP狀態碼應該是HTTP狀態碼300序列,例如301.302,具體狀態碼能夠參考HTTP協議整理
移除轉發請求的Header,多個用","分隔。默認狀況下移除以下Header。
spring: application: name: gateway cloud: nacos: discovery: server-addr: 127.0.0.1:8848 gateway: routes: - id: gate uri: lb://user predicates: #由/user-center來匹配跳轉 - Path=/user-center/** filters: #跳轉後省略第一個通配 - StripPrefix=1 filter: #移除轉發請求 remove-hop-by-hop: headers: Keep-Alive,Connection
移除原始請求頭
spring: application: name: gateway cloud: nacos: discovery: server-addr: 127.0.0.1:8848 gateway: routes: - id: gate uri: lb://user predicates: #由/user-center來匹配跳轉 - Path=/user-center/** filters: #跳轉後省略第一個通配 - StripPrefix=1 #移除原始請求頭X-Request-Foo - RemoveRequestHeader=X-Request-Foo
由spring cloud zuul網關的做用 可知,在跨域轉發中,咱們須要移除這些請求頭
spring: application: name: gateway cloud: nacos: discovery: server-addr: 127.0.0.1:8848 gateway: routes: - id: gate uri: lb://user predicates: #由/user-center來匹配跳轉 - Path=/user-center/** filters: #跳轉後省略第一個通配 - StripPrefix=1 #移除原始跨域請求頭 - RemoveRequestHeader=Access-Control-Allow-Origin filter: #移除轉發請求 remove-hop-by-hop: headers: Access-Control-Allow-Credentials,Access-Control-Allow-Origin,Vary,X-Frame-Options,token
移除響應頭
咱們在user中添加一個Controller方法
@GetMapping("/addhead") public String addHeader(HttpServletRequest request, HttpServletResponse response) { response.addHeader("X-Response-Foo","Foo"); return "header"; }
網關配置
spring: application: name: gateway cloud: nacos: discovery: server-addr: 127.0.0.1:8848 gateway: routes: - id: gate uri: lb://user predicates: #由/user-center來匹配跳轉 - Path=/user-center/** filters: #跳轉後省略第一個通配 - StripPrefix=1 #移除響應頭X-Response-Foo - RemoveResponseHeader=X-Response-Foo
經過網關轉發,咱們能夠看到無此X-Response-Foo的響應頭。
重寫請求路徑
spring: application: name: gateway cloud: nacos: discovery: server-addr: 127.0.0.1:8848 gateway: routes: - id: gate uri: lb://user predicates: #由/user-center來匹配跳轉 - Path=/user-center/** filters: #配置成原始路徑正則, 重寫後的路徑的正則 - RewritePath=/user-center/(?<segment>.*), /$\{segment}
以上配置會將/user-center/find變成/find再轉發
直接訪問user
網關請求的
重寫響應頭部份內容,根據正則來修改
以前在user中有一個Controller方法
@GetMapping("/addhead") public String addHeader(HttpServletRequest request, HttpServletResponse response) { response.addHeader("X-Response-Foo","Foo"); return "header"; }
spring: application: name: gateway cloud: nacos: discovery: server-addr: 127.0.0.1:8848 gateway: routes: - id: gate uri: lb://user predicates: #由/user-center來匹配跳轉 - Path=/user-center/** filters: #跳轉後省略第一個通配 - StripPrefix=1 #重寫響應頭X-Response-Foo的值Foo爲dee,內容可根據正則匹配 - RewriteResponseHeader=X-Response-Foo,Foo,dee
訪問user的/addhead,X-Response-Foo響應頭的值爲Foo.
經過網關訪問/addhead,X-Response-Foo響應頭的值爲dee
在轉發到後端微服務請求以前,強制執行 WebSession::save
操做。用在那種像 Spring Session
延遲數據存儲(數據不是馬上持久化)的,並但願在請求轉發前確保session狀態保存狀況。
如今咱們對user進行共享Session的配置,添加依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session-data-redis</artifactId> </dependency> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency>
添加配置
spring: redis: host: 127.0.0.1 port: 6379 password: xxxxx timeout: 10000 lettuce: pool: min-idle: 0 max-idle: 8 max-active: 8 max-wait: -1
在SpringBoot開啓共享Session
@EnableRedisHttpSession @SpringBootApplication public class UserApplication { public static void main(String[] args) { SpringApplication.run(UserApplication.class, args); } }
在user中添加以下Controller
@RestController public class SessionController { @GetMapping("/first") public Map<String,Object> firstResp(HttpServletRequest request, HttpServletResponse response) { Map<String,Object> map = new HashMap<>(); request.getSession().setAttribute("request Url",request.getRequestURL()); map.put("request Url",request.getRequestURL()); return map; } @GetMapping("/sessions") public Object sessions(HttpServletRequest request,HttpServletResponse response) { Map<String,Object> map = new HashMap<>(); map.put("SessionId",request.getSession().getId()); map.put("message",request.getSession().getAttribute("request Url")); return map; } }
咱們啓動兩個user實例,一個端口號爲8082,一個爲8083,訪問以下
咱們能夠看到除了存入Session的RequestURL不一樣之外,他們的SessionId是相同的,說明這裏是一個共享的Session。
咱們不對網關配置作修改,則咱們經過網關訪問
在訪問first的時候,它會負載均衡這兩個實例,但咱們能夠看到他在Session中存儲的是內網的IP,而不是127.0.0.1。
在網關作以下配置
spring: application: name: gateway cloud: nacos: discovery: server-addr: 127.0.0.1:8848 gateway: routes: - id: gate uri: lb://user predicates: #由/user-center來匹配跳轉 - Path=/user-center/** filters: #跳轉後省略第一個通配 - StripPrefix=1 #請求轉發前保存Session - SaveSession
目前未測出有什麼太大的做用。反而會破壞Session的數據。因此不建議增長該設置。
添加一系列起安全做用的響應頭。
默認會添加以下Header(包括值):
X-Xss-Protection:1; mode=block
防XSS攻擊設置,0: 表示關閉瀏覽器的XSS防禦機制;1:刪除檢測到的惡意代碼, 若是響應報文中沒有看到X-XSS-Protection 字段,那麼瀏覽器就認爲X-XSS-Protection配置爲1,這是瀏覽器的默認設置.1; mode=block:若是檢測到惡意代碼,在不渲染惡意代碼.Strict-Transport-Security:max-age=631138519
一個網站接受一個HTTP的請求,而後跳轉到HTTPS,用戶可能在開始跳轉前,經過沒有加密的方式和服務器對話,好比,用戶輸入http://foo.com或者直接foo.com。這樣存在中間人攻擊潛在威脅,跳轉過程可能被惡意網站利用來直接接觸用戶信息,而不是原來的加密信息。網站經過HTTP Strict Transport Security通知瀏覽器,這個網站禁止使用HTTP方式加載,瀏覽器應該自動把全部嘗試使用HTTP的請求自動替換爲HTTPS請求。X-Frame-Options:DENY
點擊劫持(ClickJacking)是一種視覺上的欺騙手段。攻擊者使用一個透明的iframe,覆蓋在一個網頁上,而後誘使用戶在網頁上進行操做,此時用戶將在不知情的狀況下點擊透明的iframe頁面。經過調整iframe頁面的位置,能夠誘使用戶剛好點擊在iframe頁面的一些功能性按鈕上。X-Content-Type-Options:nosniff
若是服務器發送響應頭 "X-Content-Type-Options: nosniff",則 script 和 styleSheet 元素會拒絕包含錯誤的 MIME 類型的響應。這是一種安全功能,有助於防止基於 MIME 類型混淆的攻擊。
簡單理解爲:經過設置"X-Content-Type-Options: nosniff"響應標頭,對 script 和 styleSheet 在執行是經過MIME 類型來過濾掉不安全的文件
服務器發送含有 "X-Content-Type-Options: nosniff" 標頭的響應時,此更改會影響瀏覽器的行爲。
Referrer-Policy:no-referrer
referrer是HTTP請求header的報文頭,用於指明當前流量的來源參考頁面。經過這個信息,咱們能夠知道訪客是怎麼來到當前頁面的。這對於Web Analytics很是重要,能夠用於分析不一樣渠道流量分佈、用戶搜索的關鍵詞等。
可是,這個字段同時會形成用戶敏感信息泄漏(如:帶有敏感信息的重置密碼URL,若被Web Analytics收集,則存在密碼被重置的危險)。
新的Referrer規定了五種策略:
Content-Security-Policy:default-src 'self' https:; font-src 'self' https: data:; img-src 'self' https: data:; object-src 'none'; script-src https:; style-src 'self' https: 'unsafe-inline'
內容安全策略(CSP),其核心思想十分簡單:網站經過發送一個 CSP 頭部,來告訴瀏覽器什麼是被受權執行的與什麼是須要被禁止的。其被譽爲專門爲解決XSS攻擊而生的神器。具體參考
http://www.javashuo.com/article/p-rmqcvuwn-ng.htmlX-Download-Options:noopen
用於放置直接打開用戶下載文件。
X-Download-Options: noopen
X-Permitted-Cross-Domain-Policies:none
用於指定當不能將"crossdomain.xml"文件(當須要從別的域名中的某個文件中讀取 Flash 內容時用於進行必要設置的策略文件)放置在網站根目錄等場合時採起的替代策略。
X-Permitted-Cross-Domain-Policies: master-only
若是你想修改這些Header的值,可以使用以下配置:
spring: application: name: gateway cloud: nacos: discovery: server-addr: 127.0.0.1:8848 gateway: routes: - id: gate uri: lb://user predicates: #由/user-center來匹配跳轉 - Path=/user-center/** filters: #跳轉後省略第一個通配 - StripPrefix=1 filter: secure-headers: xss-protection-header: 1;mode=block
上面的header對應的後綴:
xss-protection-header
strict-transport-security
frame-options
content-type-options
referrer-policy
content-security-policy
download-options
permitted-cross-domain-policies
若是想禁用某些Header,可以使用以下配置:spring.cloud.gateway.filter.secure-headers.disable
,多個用 ,
分隔。例如:
spring: application: name: gateway cloud: nacos: discovery: server-addr: 127.0.0.1:8848 gateway: routes: - id: gate uri: lb://user predicates: #由/user-center來匹配跳轉 - Path=/user-center/** filters: #跳轉後省略第一個通配 - StripPrefix=1 filter: secure-headers: disable: frame-options,download-options
spring: application: name: gateway cloud: nacos: discovery: server-addr: 127.0.0.1:8848 gateway: routes: - id: gate uri: lb://user predicates: #由/user-center來匹配跳轉 - Path=/user-center/{segment} filters: #使用/{segment}來代替/user-center/{segment}後轉發 - SetPath=/{segment}
用意跟以前差很少。
在User項目中有這樣一個Controller方法
@GetMapping("/addhead") public String addHeader(HttpServletRequest request, HttpServletResponse response) { response.addHeader("X-Response-Foo","Foo"); return "header"; }
spring: application: name: gateway cloud: nacos: discovery: server-addr: 127.0.0.1:8848 gateway: routes: - id: gate uri: lb://user predicates: #由/user-center來匹配跳轉 - Path=/user-center/** filters: #跳轉後省略第一個通配 - StripPrefix=1 #將響應頭X-Response-Foo的值更改成dee - SetResponseHeader=X-Response-Foo,dee
修改響應的狀態碼,值能夠是數字,也能夠是字符串。但必定要是Spring HttpStatus
枚舉類中的值。
spring: application: name: gateway cloud: nacos: discovery: server-addr: 127.0.0.1:8848 gateway: routes: - id: gate uri: lb://user predicates: #由/user-center來匹配跳轉 - Path=/user-center/** filters: #跳轉後省略第一個通配 - StripPrefix=1 #修改返回狀態碼爲401 - SetStatus=401
這裏是能夠正常返回結果的,只不過狀態碼被修改成401
數字表示要截斷的路徑的數量。
針對不一樣的響應作重試,可配置以下參數:
retries
: 重試次數statuses
: 須要重試的狀態碼,取值在 org.springframework.http.HttpStatus
中methods
: 須要重試的請求方法,取值在 org.springframework.http.HttpMethod
中series
: HTTP狀態碼系列,取值在 org.springframework.http.HttpStatus.Series
中spring: application: name: gateway cloud: nacos: discovery: server-addr: 127.0.0.1:8848 gateway: routes: - id: gate uri: lb://user predicates: #由/user-center來匹配跳轉 - Path=/user-center/** filters: #跳轉後省略第一個通配 - StripPrefix=1 #若是方法未找到,重試3次 - name: Retry args: retries: 3 statuses: NOT_FOUND
爲後端服務設置收到的最大請求包大小。若是請求大小超過設置的值,則返回 413 Payload Too Large
。默認值是5M
不過這裏我設置了1字節,好像不起做用。
spring: application: name: gateway cloud: nacos: discovery: server-addr: 127.0.0.1:8848 gateway: routes: - id: gate uri: lb://user predicates: #由/user-center來匹配跳轉 - Path=/user-center/** filters: #跳轉後省略第一個通配 - StripPrefix=1 #若是請求包超過1字節,返回413 - name: RequestSize args: maxSize: 1
經測試無效
可用於在Gateway將請求發送給後端微服務以前,修改請求體內容。該過濾器工廠目前處於BETA狀態,不建議使用。
可用於修改響應體內容。該過濾器工廠目前處於BETA狀態,不建議使用。
若是你想爲全部路由添加過濾器,可以使用該屬性。
spring: application: name: gateway cloud: nacos: discovery: server-addr: 127.0.0.1:8848 gateway: routes: - id: gate uri: lb://user predicates: #由/user-center來匹配跳轉 - Path=/user-center/** #該配置對全部的routes.id均有效 default-filters: #跳轉後省略第一個通配 - StripPrefix=1
自定義過濾器工廠
如今咱們來寫一個打印日誌的過濾器工廠,該自定義過濾器工廠必須以GatewayFilterFactory結尾
@Slf4j @Component public class PreLogGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory { @Override public GatewayFilter apply(NameValueConfig config) { return (((exchange, chain) -> { log.info("請求進來了...{},{}",config.getName(),config.getValue()); //獲取請求 ServerHttpRequest modifiedRequest = exchange.getRequest() .mutate() .build(); //獲取exchange ServerWebExchange modifiedExchange = exchange.mutate() .request(modifiedRequest) .build(); //傳遞給下一個過濾器 return chain.filter(modifiedExchange); })); } }
配置文件
spring: application: name: gateway cloud: nacos: discovery: server-addr: 127.0.0.1:8848 gateway: routes: - id: gate uri: lb://user predicates: #由/user-center來匹配跳轉 - Path=/user-center/** filters: #跳轉後省略第一個通配 - StripPrefix=1 #打印a,b日誌 - PreLog=a,b
運行後,咱們經過網關訪問API後,打印日誌以下
2019-12-20 14:09:48.066 INFO 2702 --- [ctor-http-nio-2] c.c.c.m.g.c.PreLogGatewayFilterFactory : 請求進來了...a,b
全局過濾器
1 Combined Global Filter and GatewayFilter Ordering
2 Forward Routing Filter
3 LoadBalancerClient Filter
4 Netty Routing Filter
5 Netty Write Response Filter
6 RouteToRequestUrl Filter
7 Websocket Routing Filter
8 Gateway Metrics Filter
9 Marking An Exchange As Routed
當請求到來時,Filtering Web Handler
處理器會添加全部 GlobalFilter
實例和匹配的 GatewayFilter
實例到過濾器鏈中。
過濾器鏈會使用 org.springframework.core.Ordered
註解所指定的順序,進行排序。Spring Cloud Gateway區分了過濾器邏輯執行的」pre」和」post」階段,因此優先級高的過濾器將會在pre階段最早執行,優先級最低的過濾器則在post階段最後執行。數值越小越靠前執行。
@Slf4j @Configuration public class GlobleFilters { @Bean @Order(-1) public GlobalFilter a() { return ((exchange, chain) -> { log.info("first pre filter"); return chain.filter(exchange).then(Mono.fromRunnable( () -> log.info("third post filter"))); }); } @Bean @Order(0) public GlobalFilter b() { return ((exchange, chain) -> { log.info("second pre filter"); return chain.filter(exchange).then(Mono.fromRunnable( () -> log.info("second post filter"))); }); } @Bean @Order(1) public GlobalFilter c() { return ((exchange, chain) -> { log.info("third pre filter"); return chain.filter(exchange).then(Mono.fromRunnable( () -> log.info("first post filter"))); }); } }
當有網關轉發請求時
2019-12-20 15:03:34.263 INFO 3380 --- [ctor-http-nio-2] c.c.c.m.gateway.config.GlobleFilters : first pre filter
2019-12-20 15:03:34.263 INFO 3380 --- [ctor-http-nio-2] c.c.c.m.gateway.config.GlobleFilters : second pre filter
2019-12-20 15:03:34.263 INFO 3380 --- [ctor-http-nio-2] c.c.c.m.gateway.config.GlobleFilters : third pre filter
2019-12-20 15:03:34.302 INFO 3380 --- [ctor-http-nio-7] c.c.c.m.gateway.config.GlobleFilters : first post filter
2019-12-20 15:03:34.302 INFO 3380 --- [ctor-http-nio-7] c.c.c.m.gateway.config.GlobleFilters : second post filter
2019-12-20 15:03:34.302 INFO 3380 --- [ctor-http-nio-7] c.c.c.m.gateway.config.GlobleFilters : third post filter
整合Sentinel限流
Sentinel的版本必須在1.6及以上,咱們這裏爲1.7
pom
<dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-spring-cloud-gateway-adapter</artifactId> </dependency>
添加配置類
@Configuration public class GatewayConfig { private final List<ViewResolver> viewResolvers; private final ServerCodecConfigurer serverCodecConfigurer; public GatewayConfig(ObjectProvider<List<ViewResolver>> viewResolverProvider, ServerCodecConfigurer serverCodecConfigurer) { this.viewResolvers = viewResolverProvider.getIfAvailable(Collections::emptyList); this.serverCodecConfigurer = serverCodecConfigurer; } @Bean @Order(Ordered.HIGHEST_PRECEDENCE) public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() { return new SentinelGatewayBlockExceptionHandler(viewResolvers,serverCodecConfigurer); } @Bean @Order(Ordered.HIGHEST_PRECEDENCE) public GlobalFilter sentinelGatewayFilter() { return new SentinelGatewayFilter(); } @PostConstruct public void doInit() { initGatewayRules(); } /** * 配置限流規則 */ private void initGatewayRules() { Set<GatewayFlowRule> rules = new HashSet<>(); rules.add(new GatewayFlowRule("gate") .setCount(1) //限流閾值 .setIntervalSec(1)); //統計時間窗口,單位是秒,默認是1秒 GatewayRuleManager.loadRules(rules); } }
咱們這裏設置的爲1秒鐘只能經過一個請求。
若是咱們在1秒鐘內請求兩次或以上,就會產生限流提示。