Spring Cloud的快速入門(二)

0.學習目標

  • 會配置Hystix熔斷
  • 會使用Feign進行遠程調(diào)用
  • 能獨立搭建Zuul網(wǎng)關
  • 能編寫Zuul的攔截器

1.Hystix

1.1.簡介

Hystix赴捞,即熔斷器可很。

主頁:https://github.com/Netflix/Hystrix/

1525658740266.png

Hystix是Netflix開源的一個延遲和容錯庫睛驳,用于隔離訪問遠程服務蒜田、第三方庫稿械,防止出現(xiàn)級聯(lián)失敗。

1525658562507.png

1.2.熔斷器的工作機制:

1525658640314.png

正常工作的情況下冲粤,客戶端請求調(diào)用服務API接口:

1525658906255.png

當有服務出現(xiàn)異常時溜哮,直接進行失敗回滾,服務降級處理:

1525658983518.png

當服務繁忙時色解,如果服務出現(xiàn)異常茂嗓,不是粗暴的直接報錯,而是返回一個友好的提示科阎,雖然拒絕了用戶的訪問述吸,但是會返回一個結(jié)果。

這就好比去買魚锣笨,平常超市買魚會額外贈送殺魚的服務蝌矛。等到逢年過節(jié),超時繁忙時错英,可能就不提供殺魚服務了入撒,這就是服務的降級。

系統(tǒng)特別繁忙時椭岩,一些次要服務暫時中斷茅逮,優(yōu)先保證主要服務的暢通,一切資源優(yōu)先讓給主要服務來使用判哥,在雙十一献雅、618時,京東天貓都會采用這樣的策略塌计。

1.3.動手實踐

1.3.1.引入依賴

首先在user-consumer中引入Hystix依賴:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

1.3.2.開啟熔斷

1.3.2.改造消費者

我們改造user-consumer挺身,添加一個用來訪問的user服務的DAO,并且聲明一個失敗時的回滾處理函數(shù):

@Component
public class UserDao {

    @Autowired
    private RestTemplate restTemplate;

    private static final Logger logger = LoggerFactory.getLogger(UserDao.class);

    @HystrixCommand(fallbackMethod = "queryUserByIdFallback")
    public User queryUserById(Long id){
        long begin = System.currentTimeMillis();
        String url = "http://user-service/user/" + id;
        User user = this.restTemplate.getForObject(url, User.class);
        long end = System.currentTimeMillis();
        // 記錄訪問用時:
        logger.info("訪問用時:{}", end - begin);
        return user;
    }

    public User queryUserByIdFallback(Long id){
        User user = new User();
        user.setId(id);
        user.setName("用戶信息查詢出現(xiàn)異常锌仅!");
        return user;
    }
}
  • @HystrixCommand(fallbackMethod="queryUserByIdFallback"):聲明一個失敗回滾處理函數(shù)queryUserByIdFallback章钾,當queryUserById執(zhí)行超時(默認是1000毫秒)墙贱,就會執(zhí)行fallback函數(shù),返回錯誤提示贱傀。
  • 為了方便查看熔斷的觸發(fā)時機嫩痰,我們記錄請求訪問時間。

在原來的業(yè)務邏輯中調(diào)用這個DAO:

@Service
public class UserService {

    @Autowired
    private UserDao userDao;

    public List<User> queryUserByIds(List<Long> ids) {
        List<User> users = new ArrayList<>();
        ids.forEach(id -> {
            // 我們測試多次查詢窍箍,
            users.add(this.userDao.queryUserById(id));
        });
        return users;
    }
}

1.3.3.改造服務提供者

改造服務提供者,隨機休眠一段時間丽旅,以觸發(fā)熔斷:

@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    public User queryById(Long id) throws InterruptedException {
        // 為了演示超時現(xiàn)象椰棘,我們在這里然線程休眠,時間隨機 0~2000毫秒
        Thread.sleep(new Random().nextInt(2000));
        return this.userMapper.selectByPrimaryKey(id);
    }
}

1.3.4.啟動測試

然后運行并查看日志:

id為9、10榄笙、11的訪問時間分別是:

1525661641660.png

id為12的訪問時間:

1525661669136.png

因此,只有12是正常訪問,其它都會觸發(fā)熔斷拄查,我們來查看結(jié)果:

1525661720656.png

1.3.5.優(yōu)化

雖然熔斷實現(xiàn)了,但是我們的重試機制似乎沒有生效,是這樣嗎匠抗?

其實這里是因為我們的Ribbon超時時間設置的是1000ms:

?
1525666632542.png

而Hystix的超時時間默認也是1000ms射赛,因此重試機制沒有被觸發(fā)秆麸,而是先觸發(fā)了熔斷坷随。

所以房铭,Ribbon的超時時間一定要小于Hystix的超時時間。

我們可以通過hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds來設置Hystrix超時時間温眉。

hystrix:
  command:
    default:
        execution:
          isolation:
            thread:
              timeoutInMillisecond: 6000 # 設置hystrix的超時時間為6000ms

2.Feign

在前面的學習中缸匪,我們使用了Ribbon的負載均衡功能,大大簡化了遠程調(diào)用時的代碼:

String baseUrl = "http://user-service/user/";
User user = this.restTemplate.getForObject(baseUrl + id, User.class)

如果就學到這里类溢,你可能以后需要編寫類似的大量重復代碼豪嗽,格式基本相同,無非參數(shù)不一樣豌骏。有沒有更優(yōu)雅的方式龟梦,來對這些代碼再次優(yōu)化呢?

這就是我們接下來要學的Feign的功能了窃躲。

2.1.簡介

有道詞典的英文解釋:

?
1525662976679.png

為什么叫偽裝计贰?

Feign可以把Rest的請求進行隱藏,偽裝成類似SpringMVC的Controller一樣蒂窒。你不用再自己拼接url躁倒,拼接參數(shù)等等操作,一切都交給Feign去做洒琢。

項目主頁:https://github.com/OpenFeign/feign

1525652009416.png

2.2.快速入門

2.2.1.導入依賴

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

2.2.2.Feign的客戶端

@FeignClient("user-service")
public interface UserFeignClient {

    @GetMapping("/user/{id}")
    User queryUserById(@PathVariable("id") Long id);
}
  • 首先這是一個接口秧秉,F(xiàn)eign會通過動態(tài)代理,幫我們生成實現(xiàn)類衰抑。這點跟mybatis的mapper很像
  • @FeignClient象迎,聲明這是一個Feign客戶端,類似@Mapper注解。同時通過value屬性指定服務名稱
  • 接口中的定義方法砾淌,完全采用SpringMVC的注解啦撮,F(xiàn)eign會根據(jù)注解幫我們生成URL,并訪問獲取結(jié)果

改造原來的調(diào)用邏輯汪厨,不再調(diào)用UserDao:

@Service
public class UserService {

    @Autowired
    private UserFeignClient userFeignClient;

    public List<User> queryUserByIds(List<Long> ids) {
        List<User> users = new ArrayList<>();
        ids.forEach(id -> {
            // 我們測試多次查詢赃春,
            users.add(this.userFeignClient.queryUserById(id));
        });
        return users;
    }
}

2.2.3.開啟Feign功能

我們在啟動類上,添加注解劫乱,開啟Feign功能

@SpringBootApplication
@EnableDiscoveryClient
@EnableHystrix
@EnableFeignClients // 開啟Feign功能
public class UserConsumerDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserConsumerDemoApplication.class, args);
    }
}
  • 你會發(fā)現(xiàn)RestTemplate的注冊被我刪除了织中。Feign中已經(jīng)自動集成了Ribbon負載均衡,因此我們不需要自己定義RestTemplate了

2.2.4.啟動測試:

訪問接口:

1525666476326.png

正常獲取到了結(jié)果衷戈。

2.3.負載均衡

Feign中本身已經(jīng)集成了Ribbon依賴和自動配置:

?
1525672070679.png

因此我們不需要額外引入依賴狭吼,也不需要再注冊RestTemplate對象。

另外脱惰,我們可以像上節(jié)課中講的那樣去配置Ribbon,可以通過ribbon.xx來進行全局配置窿春。也可以通過服務名.ribbon.xx來對指定服務配置:

user-service:
  ribbon:
    ConnectTimeout: 250 # 連接超時時間(ms)
    ReadTimeout: 1000 # 通信超時時間(ms)
    OkToRetryOnAllOperations: true # 是否對所有操作重試
    MaxAutoRetriesNextServer: 1 # 同一服務不同實例的重試次數(shù)
    MaxAutoRetries: 1 # 同一實例的重試次數(shù)

2.4.Hystix支持

Feign默認也有對Hystix的集成:

?
1525672466192.png

只不過拉一,默認情況下是關閉的。我們需要通過下面的參數(shù)來開啟:

feign:
  hystrix:
    enabled: true # 開啟Feign的熔斷功能

但是旧乞,F(xiàn)eign中的Fallback配置不像Ribbon中那樣簡單了蔚润。

1)首先,我們要定義一個類尺栖,實現(xiàn)剛才編寫的UserFeignClient嫡纠,作為fallback的處理類

@Component
public class UserFeignClientFallback implements UserFeignClient {
    @Override
    public User queryUserById(Long id) {
        User user = new User();
        user.setId(id);
        user.setName("用戶查詢出現(xiàn)異常!");
        return user;
    }
}

2)然后在UserFeignClient中延赌,指定剛才編寫的實現(xiàn)類

@FeignClient(value = "user-service", fallback = UserFeignClientFallback.class)
public interface UserFeignClient {

    @GetMapping("/user/{id}")
    User queryUserById(@PathVariable("id") Long id);
}

3)重啟測試:

我們關閉user-service服務除盏,然后在頁面訪問:

1525673049875.png

2.5.請求壓縮(了解)

Spring Cloud Feign 支持對請求和響應進行GZIP壓縮,以減少通信過程中的性能損耗挫以。通過下面的參數(shù)即可開啟請求與響應的壓縮功能:

feign:
  compression:
    request:
      enabled: true # 開啟請求壓縮
    response:
      enabled: true # 開啟響應壓縮

同時者蠕,我們也可以對請求的數(shù)據(jù)類型,以及觸發(fā)壓縮的大小下限進行設置:

feign:
  compression:
    request:
      enabled: true # 開啟請求壓縮
      mime-types: text/html,application/xml,application/json # 設置壓縮的數(shù)據(jù)類型
      min-request-size: 2048 # 設置觸發(fā)壓縮的大小下限

注:上面的數(shù)據(jù)類型掐松、壓縮大小下限均為默認值踱侣。

2.6.日志級別(了解)

前面講過,通過logging.level.xx=debug來設置日志級別大磺。然而這個對Fegin客戶端而言不會產(chǎn)生效果抡句。因為@FeignClient注解修改的客戶端在被代理時,都會創(chuàng)建一個新的Fegin.Logger實例杠愧。我們需要額外指定這個日志的級別才可以待榔。

1)設置com.leyou包下的日志級別都為debug

logging:
  level:
    com.leyou: debug

2)編寫配置類,定義日志級別

@Configuration
public class FeignConfig {
    @Bean
    Logger.Level feignLoggerLevel(){
        return Logger.Level.FULL;
    }
}

這里指定的Level級別是FULL流济,F(xiàn)eign支持4種級別:

?
1525674373507.png
  • NONE:不記錄任何日志信息究抓,這是默認值猾担。
  • BASIC:僅記錄請求的方法,URL以及響應狀態(tài)碼和執(zhí)行時間
  • HEADERS:在BASIC的基礎上刺下,額外記錄了請求和響應的頭信息
  • FULL:記錄所有請求和響應的明細绑嘹,包括頭信息、請求體橘茉、元數(shù)據(jù)工腋。

3)在FeignClient中指定配置類:

@FeignClient(value = "user-service", fallback = UserFeignClientFallback.class, configuration = FeignConfig.class)
public interface UserFeignClient {
    @GetMapping("/user/{id}")
    User queryUserById(@PathVariable("id") Long id);
}

4)重啟項目,即可看到每次訪問的日志:

1525674544569.png

3.Zuul網(wǎng)關

通過前面的學習畅卓,使用Spring Cloud實現(xiàn)微服務的架構(gòu)基本成型擅腰,大致是這樣的:

1525674644660.png

我們使用Spring Cloud Netflix中的Eureka實現(xiàn)了服務注冊中心以及服務注冊與發(fā)現(xiàn);而服務間通過Ribbon或Feign實現(xiàn)服務的消費以及均衡負載翁潘;通過Spring Cloud Config實現(xiàn)了應用多環(huán)境的外部化配置以及版本管理趁冈。為了使得服務集群更為健壯,使用Hystrix的融斷機制來避免在微服務架構(gòu)中個別服務出現(xiàn)異常時引起的故障蔓延拜马。

在該架構(gòu)中渗勘,我們的服務集群包含:內(nèi)部服務Service A和Service B,他們都會注冊與訂閱服務至Eureka Server俩莽,而Open Service是一個對外的服務旺坠,通過均衡負載公開至服務調(diào)用方。我們把焦點聚集在對外服務這塊扮超,直接暴露我們的服務地址取刃,這樣的實現(xiàn)是否合理,或者是否有更好的實現(xiàn)方式呢出刷?

先來說說這樣架構(gòu)需要做的一些事兒以及存在的不足:

  • 首先璧疗,破壞了服務無狀態(tài)特點。
    • 為了保證對外服務的安全性馁龟,我們需要實現(xiàn)對服務訪問的權(quán)限控制病毡,而開放服務的權(quán)限控制機制將會貫穿并污染整個開放服務的業(yè)務邏輯,這會帶來的最直接問題是屁柏,破壞了服務集群中REST API無狀態(tài)的特點啦膜。
    • 從具體開發(fā)和測試的角度來說,在工作中除了要考慮實際的業(yè)務邏輯之外淌喻,還需要額外考慮對接口訪問的控制處理僧家。
  • 其次,無法直接復用既有接口裸删。
    • 當我們需要對一個即有的集群內(nèi)訪問接口八拱,實現(xiàn)外部服務訪問時,我們不得不通過在原有接口上增加校驗邏輯,或增加一個代理調(diào)用來實現(xiàn)權(quán)限控制肌稻,無法直接復用原有的接口清蚀。

面對類似上面的問題,我們要如何解決呢爹谭?答案是:服務網(wǎng)關枷邪!

為了解決上面這些問題,我們需要將權(quán)限控制這樣的東西從我們的服務單元中抽離出去诺凡,而最適合這些邏輯的地方就是處于對外訪問最前端的地方东揣,我們需要一個更強大一些的均衡負載器的 服務網(wǎng)關。

服務網(wǎng)關是微服務架構(gòu)中一個不可或缺的部分腹泌。通過服務網(wǎng)關統(tǒng)一向外系統(tǒng)提供REST API的過程中嘶卧,除了具備服務路由、均衡負載功能之外凉袱,它還具備了權(quán)限控制等功能芥吟。Spring Cloud Netflix中的Zuul就擔任了這樣的一個角色,為微服務架構(gòu)提供了前門保護的作用专甩,同時將權(quán)限控制這些較重的非業(yè)務邏輯內(nèi)容遷移到服務路由層面钟鸵,使得服務集群主體能夠具備更高的可復用性和可測試性。

3.1.簡介

官網(wǎng):https://github.com/Netflix/zuul

?
1525675037152.png

Zuul:維基百科:

電影《捉鬼敢死隊》中的怪獸配深,Zuul携添,在紐約引發(fā)了巨大騷亂嫁盲。

事實上篓叶,在微服務架構(gòu)中,Zuul就是守門的大Boss羞秤!一夫當關缸托,萬夫莫開!

1525675168152.png

3.2.Zuul加入后的架構(gòu)

1525675648881.png
  • 不管是來自于客戶端(PC或移動端)的請求瘾蛋,還是服務內(nèi)部調(diào)用俐镐。一切對服務的請求都會經(jīng)過Zuul這個網(wǎng)關,然后再由網(wǎng)關來實現(xiàn) 鑒權(quán)哺哼、動態(tài)路由等等操作佩抹。Zuul就是我們服務的統(tǒng)一入口。

3.3.快速入門

3.3.1.新建工程

填寫基本信息:

1525675928548.png

添加Zuul依賴:

1525675991833.png

3.3.2.編寫啟動類

通過@EnableZuulProxy注解開啟Zuul的功能:

@SpringBootApplication
@EnableZuulProxy // 開啟Zuul的網(wǎng)關功能
public class ZuulDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(ZuulDemoApplication.class, args);
    }
}

3.3.3.編寫配置

server:
  port: 10010 #服務端口
spring: 
  application:  
    name: api-gateway #指定服務名

3.3.4.編寫路由規(guī)則

我們需要用Zuul來代理user-service服務取董,先看一下控制面板中的服務狀態(tài):

1525676797879.png
  • ip為:127.0.0.1
  • 端口為:8081

映射規(guī)則:

zuul:
  routes:
    user-service: # 這里是路由id棍苹,隨意寫
      path: /user-service/** # 這里是映射路徑
      url: http://127.0.0.1:8081 # 映射路徑對應的實際url地址

我們將符合path 規(guī)則的一切請求,都代理到 url參數(shù)指定的地址

本例中茵汰,我們將 /user-service/**開頭的請求枢里,代理到http://127.0.0.1:8081

3.3.5.啟動測試:

訪問的路徑中需要加上配置規(guī)則的映射路徑,我們訪問:http://127.0.0.1:8081/user-service/user/10

?
1525677046705.png

3.4.面向服務的路由

在剛才的路由規(guī)則中,我們把路徑對應的服務地址寫死了栏豺!如果同一服務有多個實例的話彬碱,這樣做顯然就不合理了。

我們應該根據(jù)服務的名稱奥洼,去Eureka注冊中心查找 服務對應的所有實例列表巷疼,然后進行動態(tài)路由才對!

3.4.1.添加Eureka客戶端依賴

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

3.4.2.開啟Eureka客戶端發(fā)現(xiàn)功能

@SpringBootApplication
@EnableZuulProxy // 開啟Zuul的網(wǎng)關功能
@EnableDiscoveryClient
public class ZuulDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(ZuulDemoApplication.class, args);
    }
}

3.4.3.添加Eureka配置溉卓,獲取服務信息

eureka:
  client:
    registry-fetch-interval-seconds: 5 # 獲取服務列表的周期:5s
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka
  instance:
    prefer-ip-address: true
    ip-address: 127.0.0.1

3.4.4.修改映射配置皮迟,通過服務名稱獲取

因為已經(jīng)有了Eureka客戶端,我們可以從Eureka獲取服務的地址信息桑寨,因此映射時無需指定IP地址伏尼,而是通過服務名稱來訪問,而且Zuul已經(jīng)集成了Ribbon的負載均衡功能尉尾。

zuul:
  routes:
    user-service: # 這里是路由id爆阶,隨意寫
      path: /user-service/** # 這里是映射路徑
      serviceId: user-service # 指定服務名稱

3.4.5.啟動測試

再次啟動,這次Zuul進行代理時沙咏,會利用Ribbon進行負載均衡訪問:

?
1525677821212.png

日志中可以看到使用了負載均衡器:

1525677891119.png

3.5.簡化的路由配置

在剛才的配置中辨图,我們的規(guī)則是這樣的:

  • zuul.routes.<route>.path=/xxx/**: 來指定映射路徑。<route>是自定義的路由名
  • zuul.routes.<route>.serviceId=/user-service:來指定服務名肢藐。

而大多數(shù)情況下故河,我們的<route>路由名稱往往和 服務名會寫成一樣的。因此Zuul就提供了一種簡化的配置語法:zuul.routes.<serviceId>=<path>

比方說上面我們關于user-service的配置可以簡化為一條:

zuul:
  routes:
    user-service: /user-service/** # 這里是映射路徑

省去了對服務名稱的配置吆豹。

3.6.默認的路由規(guī)則

在使用Zuul的過程中鱼的,上面講述的規(guī)則已經(jīng)大大的簡化了配置項。但是當服務較多時痘煤,配置也是比較繁瑣的凑阶。因此Zuul就指定了默認的路由規(guī)則:

  • 默認情況下,一切服務的映射路徑就是服務名本身衷快。
    • 例如服務名為:user-service宙橱,則默認的映射路徑就是:/user-service/**

也就是說,剛才的映射規(guī)則我們完全不配置也是OK的蘸拔,不信就試試看师郑。

3.7.路由前綴

配置示例:

zuul:
  prefix: /api # 添加路由前綴
  routes:
      user-service: # 這里是路由id,隨意寫
        path: /user-service/** # 這里是映射路徑
        service-id: user-service # 指定服務名稱

我們通過zuul.prefix=/api來指定了路由的前綴调窍,這樣在發(fā)起請求時宝冕,路徑就要以/api開頭。

路徑/api/user-service/user/1將會被代理到/user-service/user/1

3.8.過濾器

Zuul作為網(wǎng)關的其中一個重要功能陨晶,就是實現(xiàn)請求的鑒權(quán)猬仁。而這個動作我們往往是通過Zuul提供的過濾器來實現(xiàn)的帝璧。

3.8.1.ZuulFilter

ZuulFilter是過濾器的頂級父類。在這里我們看一下其中定義的4個最重要的方法:

public abstract ZuulFilter implements IZuulFilter{

    abstract public String filterType();

    abstract public int filterOrder();
    
    boolean shouldFilter();// 來自IZuulFilter

    Object run() throws ZuulException;// IZuulFilter
}
  • shouldFilter:返回一個Boolean值湿刽,判斷該過濾器是否需要執(zhí)行的烁。返回true執(zhí)行,返回false不執(zhí)行诈闺。
  • run:過濾器的具體業(yè)務邏輯渴庆。
  • filterType:返回字符串,代表過濾器的類型雅镊。包含以下4種:
    • pre:請求在被路由之前執(zhí)行
    • routing:在路由請求時調(diào)用
    • post:在routing和errror過濾器之后調(diào)用
    • error:處理請求時發(fā)生錯誤調(diào)用
  • filterOrder:通過返回的int值來定義過濾器的執(zhí)行順序襟雷,數(shù)字越小優(yōu)先級越高。

3.8.2.過濾器執(zhí)行生命周期:

這張是Zuul官網(wǎng)提供的請求生命周期圖,清晰的表現(xiàn)了一個請求在各個過濾器的執(zhí)行順序。

?
1525681866862.png
  • 正常流程:
    • 請求到達首先會經(jīng)過pre類型過濾器对雪,而后到達routing類型江咳,進行路由攻礼,請求就到達真正的服務提供者,執(zhí)行請求,返回結(jié)果后,會到達post過濾器捌显。而后返回響應。
  • 異常流程:
    • 整個過程中总寒,pre或者routing過濾器出現(xiàn)異常扶歪,都會直接進入error過濾器,再error處理完畢后摄闸,會將請求交給POST過濾器善镰,最后返回給用戶。
    • 如果是error過濾器自己出現(xiàn)異常贪薪,最終也會進入POST過濾器媳禁,而后返回眠副。
    • 如果是POST過濾器出現(xiàn)異常画切,會跳轉(zhuǎn)到error過濾器,但是與pre和routing不同的時囱怕,請求不會再到達POST過濾器了霍弹。

所有內(nèi)置過濾器列表:

?
1525682427811.png

3.8.3.使用場景

場景非常多:

  • 請求鑒權(quán):一般放在pre類型,如果發(fā)現(xiàn)沒有訪問權(quán)限娃弓,直接就攔截了
  • 異常處理:一般會在error類型和post類型過濾器中結(jié)合來處理典格。
  • 服務調(diào)用時長統(tǒng)計:pre和post結(jié)合使用。

3.9.自定義過濾器

接下來我們來自定義一個過濾器台丛,模擬一個登錄的校驗耍缴±危基本邏輯:如果請求中有access-token參數(shù),則認為請求有效防嗡,放行变汪。

3.9.1.定義過濾器類

@Component
public class LoginFilter extends ZuulFilter{
    @Override
    public String filterType() {
        // 登錄校驗,肯定是在前置攔截
        return "pre";
    }

    @Override
    public int filterOrder() {
        // 順序設置為1
        return 1;
    }

    @Override
    public boolean shouldFilter() {
        // 返回true蚁趁,代表過濾器生效裙盾。
        return true;
    }

    @Override
    public Object run() throws ZuulException {
        // 登錄校驗邏輯。
        // 1)獲取Zuul提供的請求上下文對象
        RequestContext ctx = RequestContext.getCurrentContext();
        // 2) 從上下文中獲取request對象
        HttpServletRequest req = ctx.getRequest();
        // 3) 從請求中獲取token
        String token = req.getParameter("access-token");
        // 4) 判斷
        if(token == null || "".equals(token.trim())){
            // 沒有token他嫡,登錄校驗失敗番官,攔截
            ctx.setSendZuulResponse(false);
            // 返回401狀態(tài)碼。也可以考慮重定向到登錄頁钢属。
            ctx.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
        }
        // 校驗通過徘熔,可以考慮把用戶信息放入上下文,繼續(xù)向后執(zhí)行
        return null;
    }
}

3.9.2.測試

沒有token參數(shù)時淆党,訪問失斀辍:

?
1525683285697.png

添加token參數(shù)后:

?
1525683354113.png

3.10.負載均衡和熔斷

Zuul中默認就已經(jīng)集成了Ribbon負載均衡和Hystix熔斷機制。但是所有的超時策略都是走的默認值宁否,比如熔斷超時時間只有1S窒升,很容易就觸發(fā)了。因此建議我們手動進行配置:

zuul:
  retryable: true
ribbon:
  ConnectTimeout: 250 # 連接超時時間(ms)
  ReadTimeout: 2000 # 通信超時時間(ms)
  OkToRetryOnAllOperations: true # 是否對所有操作重試
  MaxAutoRetriesNextServer: 2 # 同一服務不同實例的重試次數(shù)
  MaxAutoRetries: 1 # 同一實例的重試次數(shù)
hystrix:
  command:
    default:
        execution:
          isolation:
            thread:
              timeoutInMillisecond: 6000 # 熔斷超時時長:6000ms
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末慕匠,一起剝皮案震驚了整個濱河市饱须,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌台谊,老刑警劉巖蓉媳,帶你破解...
    沈念sama閱讀 219,366評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異锅铅,居然都是意外死亡酪呻,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評論 3 395
  • 文/潘曉璐 我一進店門盐须,熙熙樓的掌柜王于貴愁眉苦臉地迎上來玩荠,“玉大人,你說我怎么就攤上這事贼邓〗赘裕” “怎么了?”我有些...
    開封第一講書人閱讀 165,689評論 0 356
  • 文/不壞的土叔 我叫張陵塑径,是天一觀的道長女坑。 經(jīng)常有香客問我,道長统舀,這世上最難降的妖魔是什么匆骗? 我笑而不...
    開封第一講書人閱讀 58,925評論 1 295
  • 正文 為了忘掉前任劳景,我火速辦了婚禮,結(jié)果婚禮上碉就,老公的妹妹穿的比我還像新娘枢泰。我一直安慰自己,他們只是感情好铝噩,可當我...
    茶點故事閱讀 67,942評論 6 392
  • 文/花漫 我一把揭開白布衡蚂。 她就那樣靜靜地躺著,像睡著了一般骏庸。 火紅的嫁衣襯著肌膚如雪毛甲。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,727評論 1 305
  • 那天具被,我揣著相機與錄音玻募,去河邊找鬼。 笑死一姿,一個胖子當著我的面吹牛七咧,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播叮叹,決...
    沈念sama閱讀 40,447評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼艾栋,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了蛉顽?” 一聲冷哼從身側(cè)響起蝗砾,我...
    開封第一講書人閱讀 39,349評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎携冤,沒想到半個月后悼粮,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,820評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡曾棕,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,990評論 3 337
  • 正文 我和宋清朗相戀三年扣猫,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片翘地。...
    茶點故事閱讀 40,127評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡申尤,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出子眶,到底是詐尸還是另有隱情瀑凝,我是刑警寧澤序芦,帶...
    沈念sama閱讀 35,812評論 5 346
  • 正文 年R本政府宣布臭杰,位于F島的核電站,受9級特大地震影響谚中,放射性物質(zhì)發(fā)生泄漏渴杆。R本人自食惡果不足惜寥枝,卻給世界環(huán)境...
    茶點故事閱讀 41,471評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望磁奖。 院中可真熱鬧囊拜,春花似錦、人聲如沸比搭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽身诺。三九已至蜜托,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間霉赡,已是汗流浹背橄务。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留穴亏,地道東北人蜂挪。 一個月前我還...
    沈念sama閱讀 48,388評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像嗓化,于是被迫代替她去往敵國和親棠涮。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,066評論 2 355

推薦閱讀更多精彩內(nèi)容