spring-cloud微服务项目实战(7)- zuul构建微服务网关

目标

新建gateway网关,作为后期项目的统一网关服务

简介

zuul提供统一网关入口,屏蔽底层服务地址,规范入口地址,统一进行授权管理

部署步骤

  1. 按照前几章内容创建新子项目gateway


    spring-cloud微服务项目实战(7)- zuul构建微服务网关_第1张图片
    gateway
  2. 添加依赖,入口配置注解

        
          org.springframework.boot
            spring-boot-starter-test
            
                
                    org.springframework.boot
                    spring-boot-starter-logging
                
            
            test
        
        
            org.springframework.cloud
            spring-cloud-starter-zuul
        
        
            org.springframework.cloud
            spring-cloud-starter-eureka
        
        
            org.springframework.boot
            spring-boot-starter-log4j2
        
        
            open.template.work
            commons
            0.0.1-SNAPSHOT
        

入口配置

@SpringBootApplication
@EnableZuulProxy
public class GatewayApplication {

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

}
  1. application.yml中添加配置,zuul自动集成了Eureka,并我们屏蔽了底层服务名,采用统一前缀规范化入口,对udm-server进行格式化
eureka:
  client:
    service-url:
      defaultZone: http://root:123@peer1:8761/eureka/,http://root:123@peer2:8762/eureka/,http://root:123@peer3:8763/eureka/
  instance:
    prefer-ip-address: true
logging:
  config: classpath:log4j2-spring.xml

zuul:
#配置zuul统一前缀
  prefix: /api
#禁止所有eureka服务通过服务名直接访问
  ignored-services:
    "*"
  routes:
#将微服务需要暴露服务进行路由映射
    udm-server: /udm/**
  1. 此时访问gateway服务,访问成功


    spring-cloud微服务项目实战(7)- zuul构建微服务网关_第2张图片
    访问服务
  2. 添加过滤器,进行模拟统一权限管理,需要实现集成ZuulFilter

package open.template.work.gateway.filter;

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

@Component
public class AuthorizationFilter extends ZuulFilter {

    @Override
    public String filterType() {
        // 在进行Zuul过滤的时候可以设置其过滤执行的位置,那么此时有如下几种类型:
        // 1、pre:在请求发出之前执行过滤,如果要进行访问,肯定在请求前设置头信息
        // 2、route:在进行路由请求的时候被调用;
        // 3、post:在路由之后发送请求信息的时候被调用;
        // 4、error:出现错误之后进行调用
        return "pre";
    }

    @Override
    public int filterOrder() {
        // 设置优先级,数字越大优先级越低
        return 0;
    }

    @Override
    public boolean shouldFilter() {
        // 该Filter是否要执行
        return true;
    }

    @Override
    public Object run() {
        RequestContext currentContext = RequestContext.getCurrentContext() ; // 获取当前请求的上下文
        String appKey = currentContext.getRequest().getParameter("appKey");
        if(StringUtils.isEmpty(appKey)){
            currentContext.setSendZuulResponse(false);
            currentContext.setResponseStatusCode(200);
            currentContext.setResponseBody("{\"result\":\"权限验证失败!\"}");
            currentContext.getResponse().setContentType("text/html;charset=UTF-8");
            return null;

        }
        return null;
    }
}

如上就实现了过滤器逻辑,下面再添加个异常过滤器进行统一异常处理

package open.template.work.gateway.filter;

import com.alibaba.fastjson.JSON;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import open.template.work.commons.exception.BaseTemplateException;
import open.template.work.commons.exception.ExceptionCodeEnum;
import org.springframework.stereotype.Component;

@Component
public class ExceptionFilter extends ZuulFilter {
    @Override
    public String filterType() {
        // 在进行Zuul过滤的时候可以设置其过滤执行的位置,那么此时有如下几种类型:
        // 1、pre:在请求发出之前执行过滤,如果要进行访问,肯定在请求前设置头信息
        // 2、route:在进行路由请求的时候被调用;
        // 3、post:在路由之后发送请求信息的时候被调用;
        // 4、error:出现错误之后进行调用
        return "error";
    }

    @Override
    public int filterOrder() {
        // 该Filter是否要执行
        return 0;
    }

    @Override
    public boolean shouldFilter() {
        // 该Filter是否要执行
        return true;
    }

    @Override
    public Object run() {
        RequestContext currentContext = RequestContext.getCurrentContext();
        currentContext.setSendZuulResponse(true);
        currentContext.setResponseStatusCode(200);
        currentContext.setResponseBody(JSON.toJSONString(new BaseTemplateException(ExceptionCodeEnum.S99999)));
        currentContext.getResponse().setContentType("text/html;charset=UTF-8");
        return null;
    }
}

此时访问根据我们模拟的临时权限拦截,不传appKey将会报错


权限验证页面

但我们发现当有异常时,通过异常过滤器后会调用/error页面,此时我们还需配置ErrorHandler,此时有异常时,最后都会在/error的controller进行处理

package open.template.work.gateway.controller;

import open.template.work.commons.exception.BaseTemplateException;
import open.template.work.commons.exception.ExceptionCodeEnum;
import org.springframework.boot.autoconfigure.web.ErrorController;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ExceptionHandler implements ErrorController {

    @Override
    public String getErrorPath() {
        return "/error";
    }

    @RequestMapping("/error")
    public String error(){
        return new BaseTemplateException(ExceptionCodeEnum.S99999).toString();
    }
}

  1. 根据上一章内容,网关一样存在后端服务崩溃无法访问问题,由于网关服务属于共用服务,资源宝贵,故一样需要容错机制,下面配置zuul的fallback类
package open.template.work.gateway.fallback;

import com.netflix.hystrix.exception.HystrixTimeoutException;
import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;

@Component
public class UdmServerFallBack implements FallbackProvider {

    @Override
    public String getRoute() {
        // 表明是为哪个微服务提供回退,*表示为所有微服务提供回退
        return "*";
    }

    @Override
    public ClientHttpResponse fallbackResponse(Throwable cause) {
        if (cause instanceof HystrixTimeoutException) {
            return response(HttpStatus.GATEWAY_TIMEOUT);
        } else {
            return this.fallbackResponse();
        }
    }

    @Override
    public ClientHttpResponse fallbackResponse() {
        return this.response(HttpStatus.INTERNAL_SERVER_ERROR);
    }

    private ClientHttpResponse response(final HttpStatus status) {
        return new ClientHttpResponse() {
            @Override
            public HttpStatus getStatusCode() throws IOException {
                return status;
            }

            @Override
            public int getRawStatusCode() throws IOException {
                return status.value();
            }

            @Override
            public String getStatusText() throws IOException {
                return status.getReasonPhrase();
            }

            @Override
            public void close() {
            }

            @Override
            public InputStream getBody() throws IOException {
            //编码保持一致,防止中文乱码
                return new ByteArrayInputStream("服务升级中....".getBytes("UTF-8"));
            }

            @Override
            public HttpHeaders getHeaders() {
                // headers设定
                HttpHeaders headers = new HttpHeaders();
                MediaType mt = new MediaType("application", "json", Charset.forName("UTF-8"));
                headers.setContentType(mt);
                return headers;
            }
        };
    }

}

好了,到此zuul在微服务的使用基本介绍完了。当然还有zuul的一些其他应用并没有细说,如对非jvm应用的支持(sidecar技术)、各种路由规则等等,可以参考《spring cloud 微服务实战》学习

你可能感兴趣的:(spring-cloud微服务项目实战(7)- zuul构建微服务网关)