[java]微服务架构连载No6 服务保护门之网关Zuul

Zuul说明:

网络请求入口,服务路由,负载均衡,权限控制,为微服务架构提供了前门保护作用,同时将权限控制这些较重的非业务逻辑内容迁移到服务器路由层面,是的服务集群主体能够具备跟高的可复用性和可测试性,并且支持负载均衡ribbon和和断路器hystrix功能


工程结构 

spring-cloud-05-zuul-hello-provider [hello模块服务发布端]

spring-cloud-05-zuul-luck-provider [luck模块服务发布端]

spring-cloud-05-zuul-eureka [服务注册中心]

spring-cloud-05-zuul-hello-getway [服务网关]


spring-cloud-05-zuul-eureka [服务注册中心] 代码同上篇,不做说明


spring-cloud-05-zuul-hello-provider [hello模块服务发布端]

@RestController
public class HelloController {

    @GetMapping("/hello")
    public String hello() {
        System.err.println("---hello zuul --");
        return "--- hello zuul-----";
    }

    @GetMapping("/token")
    public String token(@RequestHeader("userId") String userId,@RequestHeader("roleId") String roleId) {
        System.err.println("---hello zuul --");
        return "--- token zuul ,userId="+userId+" , roleId="+roleId+ " --";
    }

    @PostMapping("/upload")
    public String hello(@RequestParam("file") MultipartFile file) {
        System.err.println("---hello 附件名称:"+file.getOriginalFilename());

        try {
            FileUtils.writeByteArrayToFile(new File("/Users/wlx/sxt/code/spring-cloud-master/spring-cloud-05-zuul-hello-provider/src/main/resources/META-INF/resources/"+file.getOriginalFilename()),file.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
            return "--- upload zuul error  --";
        }
        return "--- upload zuul ok  --";
    }


}

备注: 发布两个服务

/hello 普通服务

/token 需要网关权限验证服务

/upload 附件上传服务


spring:
  application:
    name: hello-provider
  http:
    encoding:
      charset: UTF-8
    multipart:
      enabled: true   #启用
      file-size-threshold: 10 #当数据量大于该值时,内容将被写入文件。
      max-file-size: 50MB   #最大文件大小
      max-request-size: 100MB   # 请求信息大小(包含文字等信息)

server:
  port: 7001
  context-path: /

eureka:
  client:
    service-url:
     defaultZone: http://localhost:8001/eureka/


备注: 使用http.multipart上传附件配置

端口: 7001


@SpringBootApplication
@EnableDiscoveryClient
public class HelloApplication {

    public static void main(String[] args) {
        SpringApplication.run(HelloApplication.class, args);
    }
}
备注: @EnableDiscoveryClient注册到配置中心


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div>
    <form action="http://17.9.16.101:7003/hello-service/upload" enctype="multipart/form-data" method="post">
        <input type="file" name="file" /></br>
        <input type="submit" value="普通上传" />
    </form>
</div>

</hr>
<div>
    <!--说明:通过下面的代码发现前面多了一个 zuul,表示绕过zuul的内部DispatchServlet直接路由到我们的具体微服务,
         这样可以避免二次配置(文件大小..., servle默认限制为10兆),并且非常方便,
        只要符合 /zuul/*的配置即可-->
    <form action="http://17.9.16.101:7003/zuul/hello-service/upload" enctype="multipart/form-data" method="post">
        <input type="file" name="file" /></br>
        <input type="submit" value="通过zuul网关地址上传" />
    </form>
</div>
</body>
</html>

备注: 1:路径: resources/META-INF/resources/index.html

2: 两种方式实现附件上传, 第一种没有加 zuul/ 如果在上传附件大于10MB的时候, 网关zuul的DispatchServlet 就会拦截服务,

第二种加了zuul,绕过网关zuul的内部DispatchServlet直接路由到我们的具体微服务,hello-provider,由于服务配置的最大文件大小为40MB, 此时如果附件

大于10MB是ok的

spring-cloud-05-zuul-luck-provider [luck模块服务发布端]

@RestController
public class LuckController {

    @GetMapping("/luck")
    public String hello() throws InterruptedException {
        System.err.println("---luck zuul --");
        return "--- luck zuul --";
    }


}

备注: 添加服务 /luck


spring:
  application:
    name: luck-provider

server:
  port: 7002
  context-path: /

eureka:
  client:
    service-url:
     defaultZone: http://localhost:8001/eureka/

备注:服务端口号7002


spring-cloud-05-zuul-hello-getway [服务网关]

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-eureka</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-zuul</artifactId>
    </dependency>
</dependencies>
备注: 导入 spring-cloud-starter-zuul 包依赖


spring:
  application:
    name: getway-consumer

server:
  port: 7003
  context-path: /

eureka:
  client:
    service-url:
     defaultZone: http://localhost:8001/eureka/

#路由规则
zuul:
  routes:
    api-hello:  #自定义
      path: /hello-service/**   #自定义
      service-id: hello-provider  # 服务名称
    api-luck:
      path: /luck-service/**
      service-id: luck-provider

备注  1: 服务端口 7003

2: 定义路由规则,注意 service-id 要置顶服务名称


@SpringBootApplication
@EnableDiscoveryClient
@EnableZuulProxy //启动zuul
public class GetwayApplication {


    public static void main(String[] args) {
        SpringApplication.run(GetwayApplication.class, args);
    }
}
备注: 通过 @EnableZuulProxy  启动zuul


@Component //注入到spring容器
public class CustomAuthFilter extends ZuulFilter {


    /**
     *  pre:再请求被路由之前调用
     *  routing: 再请求被路由之中调用
     *  post: 再请求被路由之后调用
     *  error: 处理请求发生错误时调用
     */
    @Override
    public String filterType() {
        return "pre" ;  // post/error/routing
    }

    /**
     * 多个路由情况,该路由执行优先级, 值越小优先级越高
     */
    @Override
    public int filterOrder() {
        return 0;
    }

    /**
     * 是否执行 (启动)
     * @return
     */
    @Override
    public boolean shouldFilter() {
        return true;
    }

    /**
     * 执行内容,业务自己编写
     */
    @Override
    public Object run() {

        //http请求 --> zuul (run 方法)  ---> requestContext
        RequestContext ctx = RequestContext.getCurrentContext();

        HttpServletRequest request =ctx.getRequest();

        String token =request.getHeader("token");

        String uri =request.getRequestURI();
        if(uri.contains("hello-service/upload") || uri.contains("hello-service/hello") || uri.contains("hi-service/luck")){
            return ctx;
        }

        if(StringUtils.isEmpty(token)){
            System.err.println("---------no token,auth faild ------------  ");
            ctx.setSendZuulResponse(false);
            ctx.setResponseStatusCode(401);
            ctx.setResponseBody("---------no token,auth faild ------------  ");
            return null ;
        }

        ctx.addZuulRequestHeader("userId","11");
        ctx.addZuulRequestHeader("roleId","121");

        return ctx;
    }
}

备注: 1:添加网关过滤器,可进行权限控制,实现ZuulFilter ,并重写 filterType/filterType/shouldFilter/run, 含义见备注

2: 对服务 hello / luck /upload 不进行权限校验,直接路由到服务


/**
 * desc  指定断熔某个服务/自定义响应内容
 *
 */

@Component
public class HelloServiceZuulFailBackProvider  implements ZuulFallbackProvider{

    //指定要段熔的服务名: appName
    @Override
    public String getRoute() {
        return "hello-service";
    }

    @Override
    public ClientHttpResponse fallbackResponse() {
        return new ClientHttpResponse() {
            @Override
            public HttpStatus getStatusCode() throws IOException {
                return HttpStatus.BAD_REQUEST;
            }

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

            //状态文本信息
            @Override
            public String getStatusText() throws IOException {
                return this.getStatusCode().getReasonPhrase();
            }

            @Override
            public void close() {

            }

            @Override
            public InputStream getBody() throws IOException {
                return new ByteArrayInputStream("-----service error----".getBytes());
            }

            //response 相应头信息
            @Override
            public HttpHeaders getHeaders() {
                HttpHeaders httpHeaders =new HttpHeaders();
                httpHeaders.setContentType(MediaType.APPLICATION_JSON);
                return httpHeaders;
            }
        };
    }

备注: 1: 置顶某个服务段熔策略,可自定义实现方法

2: 实现ZuulFallbackProvider接口,实现自定义方法内容


运行期望结果:

截图1: 服务注册中心 四个服务正常启动

截图2: 通过网关地址 http://17.9.16.101:7003/hello-service/hello 和  http://17.9.16.101:7003/luck-service/luck 路由到不同的服务地址,调用服务和返回不同结果

截图3:  通过网关地址http://17.9.16.101:7003/hello-service/token, 会进行头部token校验,通过调用服务,不通过直接返回

截图4: 通过html,http://17.9.16.101:7001/index.html,附件上传30MB附件,普通情况,网关校验,大于10MB上传失败,添加zuul绕过网关,通过服务配置,上传成功

截图5:服务段熔,自定义结果


截图一:



截图二:



截图三:



截图四:失败



截图四:成功







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

源14

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值