早上好!新一天又开始啦!有什么打算呢?

编程开发

Spring Cloud 微服务入门教程(八):Spring Cloud Zuul 服务网关动态路由和Cookie头信息传递和跨域

2020年02月28日 22:56:21 · 本文共 5,201 字阅读时间约 18分钟 · 4,190 次浏览
Spring Cloud 微服务入门教程(八):Spring Cloud Zuul 服务网关动态路由和Cookie头信息传递和跨域

上一节我们讲了微服务只间通过消息队列实现异步通讯,本节将介绍微服务中的网关Spring Cloud Zuul,可以实现统一管理众多的接口、实现负载均衡等功能。

新建一个网关模块

新建一个Maven的网关模块,依赖spring-cloud-starter-netflix-zuul,修改POM文件:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>cloud</artifactId>
        <groupId>net.renfei</groupId>
        <version>1.0.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <groupId>net.renfei</groupId>
    <artifactId>gateway</artifactId>
    <version>1.0.0</version>
    
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>
    </dependencies>
</project>

添加一个程序启动类,作为启动入口,并增加@EnableZuulProxy注解:

package net.renfei.gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@EnableZuulProxy
@EnableEurekaClient
@SpringBootApplication
public class GatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }
}

以及配置文件bootstrap.yml,可以实现动态获取配置,为了方便演示,我将配置直接写入bootstrap.yml,现实中是写到Git远程配置中心的:

spring:
  application:
    name: Gateway
  cloud:
    config:
      discovery:
        service-id: config
        enabled: true
      profile: dev
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
server:
  port: 8080
zuul:
  routes:
    democlientroute:
      path: /DC/**
      service-id: DemoClient
      sensitiveHeaders:
    demoserviceroute:
      path: /DS/**
      service-id: DemoService
  ignored-patterns:
    - /admin
    - /myadmin

zuul.routes后面的名称是可以自己定义的,path是指请求的路径匹配,service-id是对应路由到哪个服务的服务名称,sensitiveHeaders的作用是为了让Zuul将请求的头信息包括Cookie转发给后端服务,这个配置默认是在org.springframework.cloud.netflix.zuul.filters.ZuulProperties#sensitiveHeaders,我们可以看到默认的是private Set<String> sensitiveHeaders = new LinkedHashSet(Arrays.asList("Cookie", "Set-Cookie", "Authorization"));,如果你的头信息不是这三个,可以自己在配置文件中自定义。ignored-patterns的意思是忽略这些地址不做转发。

Zuul的过滤器

网关Zuul的核心其实就是一堆过滤器,所以在网关这里会写很多过滤器,由于有点多,我直接上一个表格:

类型顺序过滤器功能
pre-3ServletDetectionFilter标记处理 Servlet 的类型
pre-2Servlet30WrapperFilter包装 HttpServletRequest 请求
pre-1FormBodyWrapperFilter包装请求体
route1DebugFilter标记调试标志
route5PreDecorationFilter处理请求上下文供后续使用
route10RibbonRoutingFilterserviceId
route100SimpleHostRoutingFilterurl 请求转发
route500SendForwardFilterforward 请求转发
post0SendErrorFilter处理有错误的请求响应
post1000SendResponseFilter处理正常的请求响应

我们去继承com.netflix.zuul.ZuulFilter,看看都有哪些设置:

package net.renfei.gateway.filter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.stereotype.Component;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_DECORATION_FILTER_ORDER;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;
/**
 * 授权过滤器,可以判断用户是否有权访问
 *
 * @author RenFei
 */
@Component
public class AuthorizationFilter extends ZuulFilter {
    @Override
    public String filterType() {
        return PRE_TYPE;
    }
    @Override
    public int filterOrder() {
        return PRE_DECORATION_FILTER_ORDER - 1;
    }
    @Override
    public boolean shouldFilter() {
        return true;
    }
    @Override
    public Object run() throws ZuulException {
        //在此处执行判断逻辑
        return null;
    }
}

是不是很简单,先设置一个类型,然后设置执行的顺序,run()里面执行我们想要做的逻辑。

Zuul路由的动态刷新

网关会管理众多的服务接口,如果每次配置都重启非常影响生产,之前的章节我们已经搭建好SpringCloudBUS消息总线,实现了动态配置更新,我们就利用BUG总线消息刷新配置,POM中依赖spring-cloud-starter-config,然后我们新建一个配置类,加上@RefreshScope注解就可以实现动态刷新了。由于我是演示,就不去Git上面折腾配置文件了,给出参考代码:

package net.renfei.gateway.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
import org.springframework.stereotype.Component;
/**
 * Zuul的配置实现动态从配置中心拉取
 *
 * @author RenFei
 */
@Component
public class ZuulConfig {
    @RefreshScope
    @ConfigurationProperties("zuul")
    public ZuulProperties zuulProperties() {
        return new ZuulProperties();
    }
}

Zuul网关的跨域设置

我们新建一个配置类CorsConfig,注册一个Bean:CorsFilter然后进行设置,代码如下:

package net.renfei.gateway.config;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import java.util.Arrays;
/**
 * 跨域配置
 *
 * @author RenFei
 */
@Component
public class CorsConfig {
    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        //是否支持Cookie跨域
        config.setAllowCredentials(true);
        //原始域列表
        config.setAllowedOrigins(Arrays.asList("*"));
        //允许的头
        config.setAllowedHeaders(Arrays.asList("*"));
        //允许的方法,GET、POST....
        config.setAllowedMethods(Arrays.asList("*"));
        //允许跨域时间,时间段内不再检查跨域
        config.setMaxAge(300L);
        urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", config);
        return new CorsFilter(urlBasedCorsConfigurationSource);
    }
}

代码中已经有了注释,就不再啰嗦了,一个基本的网关就搭建好了。

商业用途请联系作者获得授权。
版权声明:本文为博主「任霏」原创文章,遵循 CC BY-NC-SA 4.0 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.renfei.net/posts/1003329
评论与留言

以下内容均由网友提交发布,版权与真实性无法查证,请自行辨别。

微信搜一搜:任霏博客