微服務網關
在微服務環境下,不同的服務有其不同的網絡地址,若讓客戶端直接與各個微服務通信,客戶端會多次請求不同微服務,存在跨域請求,處理相對複雜。此時我們就需要使用微服務網關。微服務網關介於服務端與客戶端的中間層,所有外部服務請求都會先經過微服務網關,客戶只能跟微服務網關進行交互,無需調用特定微服務接口,使得開發得到簡化。服務網關是在微服務前邊設置一道屏障,請求先到服務網關,網關會對請求進行過慮、校驗、路由等處理。有了服務網關可以提高微服務的安全性,網關校驗請求的合法性,請求不合法將被攔截,拒絕訪問。
Zuul簡介
Spring Cloud Zuul是整合Netflix公司的Zuul開源項目實現的微服務網關,它的核心是一組過濾器,它實現了請求路由、負載均衡、校驗過慮等 功能。
zuul與nginx整合使用
nginx: 負載均衡,反向代理
zuul: 攔截非法請求,保證請求的合法性,負載均衡
下面是網上找的一張圖
搭建網關工程
pom依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
因爲zuul網關需要獲取微服務地址,所以添加了eureka-client的依賴
在application啓動類上添加註解,標記此服務是一個網關
@EnableZuulProxy//此工程是一個zuul網關
在 application.yml 文件中配置 eureka
eureka:
client:
registerWithEureka: true #服務註冊開關
fetchRegistry: true #服務發現開關
serviceUrl: #Eureka客戶端與Eureka服務端進行交互的地址,多箇中間用逗號分隔
defaultZone: http://localhost:50101/eureka/
instance:
prefer-ip-address: true #將自己的ip地址註冊到Eureka服務中
ip-address: 127.0.0.1
instance-id: zuul50201 #指定實例id
ribbon:
MaxAutoRetries: 2 #最大重試次數,當Eureka中可以找到服務,但是服務連不上時將會重試,如果eureka中找不到服務則直接走斷路器
MaxAutoRetriesNextServer: 3 #切換實例的重試次數
OkToRetryOnAllOperations: false #對所有操作請求都進行重試,如果是get則可以,如果是post,put等操作沒有實現冪等的情況下是很危險的,所以設置爲false
ConnectTimeout: 5000 #請求連接的超時時間
ReadTimeout: 6000 #請求處理的超時時間
zuul具有代理的功能,將請求轉發給服務
配置路由: application.yml配置
配置zuul網關根路徑 /api 和端口
server:
port: 50201
servlet:
context-path: /api
配置路由
zuul:
routes:
manager-test1: #路由名稱,名稱任意,保持所有路由名稱唯
path: /test1/** #路徑匹配規則,如果不匹配,不會轉發請求
serviceId: xc-service-manage-test1 #服務id,從Eureka中找到服務的ip和端口
#url: http://localhost:31200 #也可指定url,不用 serviceId
strip-prefix: false #true:代理轉發時去掉前綴,false:代理轉發時不去掉前綴 /test/是前綴,
sensitiveHeaders: #默認zuul會屏蔽cookie,cookie不會傳到下游服務,這裏設置爲空則取消默認的黑名單,如果設置了具體的頭信息則不會傳到下游服務
ignoredHeaders: #可以設置過慮的頭信息,默認爲空表示不過慮任何頭
測試
服務端創建倆個方法請求路徑分別爲帶前綴,跟不帶前綴
請求http://localhost:50201/api/test1/hello
訪問結果
請求被轉發到 http://ip:port/test1/hello 因爲 strip-prefix爲false,所以請求有攜帶 test1
把strip-prefix 改爲true,再測試
過濾器:
Zuul的核心就是過慮器,通過過慮器實現請求過慮,身份校驗等
自定義過慮器需要繼承 ZuulFilter,ZuulFilter是一個抽象類,需要覆蓋它的四個方法,
1、 shouldFilter:返回一個Boolean值,判斷該過濾器是否需要執行。返回true表示要執行此過慮器,否則不執行。
2、 run:過濾器的業務邏輯。
3、 filterType:返回字符串代表過濾器的類型,如下
pre:請求在被路由之執行
routing:在路由請求時調用
post:在routing和errror過濾器之後調用
error:處理請求時發生錯誤調用
4、 filterOrder:此方法返回整型數值,通過此數值來定義過濾器的執行順序,數字越小優先級越高。
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class LoginFilterTest extends ZuulFilter {
@Override
public String filterType() {
return "pre";
}
@Override
public int filterOrder() {
return 2; //返回值越小,優先級越高
}
@Override
public boolean shouldFilter() {
return true; //是否執行該過濾器
}
@Override
public Object run() throws ZuulException {
//zuul 提供的 requestcontext類,可以用此類獲取request,response
RequestContext currentContext = RequestContext.getCurrentContext();
HttpServletRequest request = currentContext.getRequest();
HttpServletResponse response = currentContext.getResponse();
//取出頭部信息Authorization
String authorization = request.getHeader("Authorization");
if (StringUtils.isBlank(authorization)){
//沒有攜帶信息
// 拒絕訪問
currentContext.setSendZuulResponse(false);
currentContext.setResponseStatusCode(200); //設置響應碼
//設置響應信息
currentContext.setResponseBody("不是登陸請求啊");
response.setContentType("text/plain;charset=UTF-8");
}
return null;
}
}
測試
然後我使用 postman 發送請求
一切順利,嘿嘿