SpringCloud學習之zuul

一。爲何要有網關

  咱們先看一個圖,若是按照consumer and server(最初的調用方式),以下所示java

  這樣咱們要面臨以下問題:spring

  1. 用戶面臨着一對N的問題既用戶必須知道每一個服務。隨着服務的增多不免會....express

  2.消費端(在這裏多是服務,也有可能爲controller等),如何進行安全控制?好比說對調用者身份的驗證,防止爬蟲,或者限制IP在必定時間內的請求數?apache

  3.即使作了這些驗證,那麼每一個消費端都要重複的編寫代碼?會不會形成冗餘?json

  那麼解決這些問題,咱們不妨進行改造一下:後端

  

  這樣咱們能夠將一對N轉成了一對一,用戶只需跟網關打交道就行了,這樣咱們能夠在網關裏處理身份驗證等安全性問題,何樂而不爲呢安全

 

二。SpringCloud中的zuul

  Zuul 是在雲平臺上提供動態路由,監控,彈性,安全等服務框架,Zuul 至關因而設備和 Netflix 流應用的 Web 網站後端全部請求的前門。同時Zuul使用一系列不一樣類型的過濾器,使咱們可以快速,靈活地將功能應用於咱們的安全服務。這些過濾器可幫助咱們執行如下功能:app

  • 身份驗證和安全性 - 識別每一個資源的身份驗證要求並拒毫不符合要求的請求。框架

  • 洞察和監測 - 跟蹤有意義的數據和統計數據,以便爲咱們提供準確的生產視圖。less

  • 動態路由 - 根據須要動態路由請求到不一樣的後端羣集。

  • 壓力測試 - 逐漸增長羣集流量以衡量性能。

  • 加載Shedding - 爲每種類型的請求分配容量並刪除超出限制的請求。

  • 靜態響應處理 - 直接在邊緣創建一些響應,而不是將它們轉發到內部羣集

  • 多區域彈性 - 跨AWS區域的路由請求,以便擴大咱們的ELB使用範圍。

 

  1.首先咱們先添加spring-cloud對zuul的依賴:

compile('org.springframework.cloud:spring-cloud-starter-zuul')

  2.咱們建立application.yml配置文件:

 

spring:
  application:
    name: gateway-server
server:
  port: 8080
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8000/eureka
zuul:
  routes:
    orders:
      path: /orders/**
      #url: http://www.baidu.com
      serviceId: ORDER-SERVER
    pay:
      path: /pay/**
      serviceId: PAY-SERVER
View Code

 

 

  3.編寫啓動類

package com.zhibo.springcloud.zuul;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;

@SpringBootApplication
@EnableDiscoveryClient
@EnableZuulProxy
public class ZuulApplication {

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

 

  注意@EnableZuulProxy是@EnableZuulServer的一個超集,咱們能夠經過源代碼發現 org.springframework.cloud.netflix.zuul.ZuulProxyAutoConfiguration繼承了ZuulServerAutoConfiguration

三。 zuul中的filter

  4.1 filter(過濾器)是一個很重要的概念,它能夠在真正的請求以前進行必要的業務操做,好比說驗證等。那麼在zuul中過濾器最核心的接口爲IZuulFilter,該接口定義很是簡單: 

/*
 * Copyright 2013 Netflix, Inc.
 *
 *      Licensed under the Apache License, Version 2.0 (the "License");
 *      you may not use this file except in compliance with the License.
 *      You may obtain a copy of the License at
 *
 *          http://www.apache.org/licenses/LICENSE-2.0
 *
 *      Unless required by applicable law or agreed to in writing, software
 *      distributed under the License is distributed on an "AS IS" BASIS,
 *      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *      See the License for the specific language governing permissions and
 *      limitations under the License.
 */
package com.netflix.zuul;

import com.netflix.zuul.exception.ZuulException;

/**
 * BAse interface for ZuulFilters
 *
 * @author Mikey Cohen
 *         Date: 10/27/11
 *         Time: 3:03 PM
 */
public interface IZuulFilter {
    /**
     * a "true" return from this method means that the run() method should be invoked
     *
     * @return true if the run() method should be invoked. false will not invoke the run() method
     */
    boolean shouldFilter();

    /**
     * if shouldFilter() is true, this method will be invoked. this method is the core method of a ZuulFilter
     *
     * @return Some arbitrary artifact may be returned. Current implementation ignores it.
     * @throws ZuulException if an error occurs during execution.
     */
    Object run() throws ZuulException;

}
View Code

  而ZuulFilter是一個實現IZuulFilter接口的抽象類,這個類在接口的基礎上又添加了以下抽象方法

/**
     * to classify a filter by type. Standard types in Zuul are "pre" for pre-routing filtering,
     * "route" for routing to an origin, "post" for post-routing filters, "error" for error handling.
     * We also support a "static" type for static responses see  StaticResponseFilter.
     * Any filterType made be created or added and run by calling FilterProcessor.runFilters(type)
     *
     * @return A String representing that type
     */
    abstract public String filterType();

    /**
     * filterOrder() must also be defined for a filter. Filters may have the same  filterOrder if precedence is not
     * important for a filter. filterOrders do not need to be sequential.
     *
     * @return the int order of a filter
     */
    abstract public int filterOrder();
View Code

  我在這裏簡單解釋一下這幾個方法做用:

  filterType:定義過濾器的類型:常見的有pre(預處理階段) post(請求原始服務以前) error(發生錯誤之後) route(請求原始服務以後)

  filterOrder:定義多個過濾器的優先級,值越小優先級越高

  shouldFilter:值若是爲true,那麼終會執行run()方法

  run : 過濾器實際上執行的內容

 

  4.2 RequestContext是ConcurrentMap的一個子類,這個類能夠拿到HttpServletRequest與HttpServletResponse,同時這個類當中的數據能夠被多個zuulFilter共享,其中有幾個方法值得咱們注意如下:

   getCurrentContext() 獲取ThreadLocal中的RequestContext對象

   setSendZuulResponse() 若是設置爲false那麼將終止對原始地址的路由

   setResponseStatusCode() 設置http的狀態響應碼

   addZuulResponseHeader() 設置響應頭,經過這個方法咱們能解決響應時中文亂碼問題

   setResponseBody() 設置響應體

 

  4.3 代碼示例:實現用戶名驗證 

 

package com.zhibo.springcloud.zuul;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

@Component
public class ValidateUserZuulFilter extends ZuulFilter {

    /**
     *
     * @return
     */
    @Override
    public String filterType() {
        return "pre";
    }

    @Override
    public int filterOrder() {
        return 0;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() throws ZuulException {
        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletRequest request = requestContext.getRequest();
        String loginName = request.getParameter("loginName");
        if (loginName == null || !"admin".equals(loginName)) {
            requestContext.setSendZuulResponse(false);
            requestContext.setResponseStatusCode(500);
            Gson gson = new GsonBuilder().create();
            requestContext.addZuulResponseHeader("content-type", "application/json;charset=utf-8");
            requestContext.setResponseBody(gson.toJson(new ResponseEntity("沒有登陸名", HttpStatus.CONFLICT)));
            return null;
        }
        return null;
    }
}
View Code

 

 

四。zuul中超時的設置總結

  在這篇文章裏已經很詳細的說明了,請你們參考:周立的Springcloud超時總結

相關文章
相關標籤/搜索