1. 程式人生 > >SpringCloud之網關服務(gateway)

SpringCloud之網關服務(gateway)

quest cat jmeter 屏蔽 sign gin thead roc run

前言

網關服務在SpringCloud中有很重要的作用。
技術分享圖片

可以將服務跟外網進行隔離起到一定的保護作用,同時服務間局域網通信更加快捷。而且在網關中可以做限流、權限校驗,使得服務更加專註自身業務。比如說下訂單需要登錄權限,限流,我們在本篇將介紹如何使用。

搭建網關項目

技術分享圖片
註意:需要添加Eureka Discovery,Zuul路由組件。

1.入口添加@EnableZuulProxy註解

技術分享圖片
2.配置文件

server:
  port: 9000

#指定註冊中心地址
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

#服務的名稱
spring:
  application:
    name: api-gateway

#自定義路由映射
zuul:
  routes:
    order-service: /apigateway/order/**
    product-service: /apigateway/product/**
  #統一入口為上面的配置,其他入口忽略
  ignored-patterns: /*-service/**
  #處理http請求頭為空的問題
  sensitive-headers:

我們啟動EurekaServer、productService、OrderService、apigateway,通過訪問:
技術分享圖片
技術分享圖片
統一對外只允許apigateway/product/,apigateway/order/形式訪問接口,這樣就對外做了一次屏蔽,隱藏了真實的服務api。

網關上做權限校驗

權限校驗需要通過實現ZuulFilter進行攔截。

package com.ckmike.api_gateway.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.apache.commons.lang.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

/**
 * LoginFilter 簡要描述
 * <p> TODO:描述該類職責 </p>
 *
 * @author ckmike
 * @version 1.0
 * @date 18-11-24 下午3:53
 * @copyright ckmike
 **/
@Component
public class LoginFilter extends ZuulFilter {

    public static final String PRE_TYPE = "pre";

    // 前置過濾器
    @Override
    public String filterType() {
        return PRE_TYPE;
    }

    // 過濾順序
    @Override
    public int filterOrder() {
        return 4;
    }

    @Override
    public boolean shouldFilter() {

        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletRequest request = requestContext.getRequest();

        System.out.println("address:" + request.getRemoteAddr());
        System.out.println("uri:" + request.getRequestURI());
        System.out.println("url:" + request.getRequestURL());
        // 這裏可以結合ACL進行本地化或者放入到redis
        if ("/apigateway/order/api/v1/order/saveforribbon".equalsIgnoreCase(request.getRequestURI())) {
            return true;
        }
        return false;
    }

    @Override
    public Object run() throws ZuulException {
        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletRequest request = requestContext.getRequest();
        String token = request.getHeader("token");
        if (StringUtils.isBlank(token)) {
            token = request.getParameter("token");
        }
        if (StringUtils.isBlank(token)) {
            requestContext.setSendZuulResponse(false);
            requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
        }
        return null;
    }
}

啟動之後訪問對應的接口
技術分享圖片
到此說明我們以及做好網關的權限校驗,通常我們都會結合redis+ACL方式進行,但這裏因為簡單我直接通過字符串進行校驗,有興趣可自行擴展redis+ACl做。

網關限流

通常系統都有一個承受極限,我們通常可以nginx做一限流,我們也可以通過網關進行限流,網關限流是通過每秒生成令牌作為訪問通行標識,這裏使用了guava做令牌生成。代碼如下:

package com.ckmike.api_gateway.filter;

import com.google.common.util.concurrent.RateLimiter;
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.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

/**
 * OrderRateLimiteFilter 簡要描述
 * <p> TODO:描述該類職責 </p>
 *
 * @author ckmike
 * @version 1.0
 * @date 18-11-24 下午5:33
 * @copyright ckmike
 **/
@Component
public class OrderRateLimiteFilter extends ZuulFilter {

    public static final String PRE_TYPE = "pre";
    //每秒鐘產生1000個令牌,guava
    private static final RateLimiter rateLimiter = RateLimiter.create(1000);

    @Override
    public String filterType() {
        return PRE_TYPE;
    }

    @Override
    public int filterOrder() {
        return -4;
    }

    @Override
    public boolean shouldFilter() {

        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletRequest request = requestContext.getRequest();
        if ("/apigateway/order/api/v1/order/saveforribbon".equalsIgnoreCase(request.getRequestURI())) {
            return true;
        }
        return false;
    }

    @Override
    public Object run() throws ZuulException {
        RequestContext requestContext = RequestContext.getCurrentContext();
        if (!rateLimiter.tryAcquire()) {
            requestContext.setSendZuulResponse(false);
            requestContext.setResponseStatusCode(HttpStatus.TOO_MANY_REQUESTS.value());
        }
        return null;
    }
}

我們可以通過jmeter進行壓力測試,對/apigateway/order/api/v1/order/saveforribbon接口進行壓力測試,這樣我們就可以很好的測試上面的內容。

SpringCloud之網關服務(gateway)