Spring Cloud集成Zuul

Zuul反向代理

当集群服务很多的情况下,外部服务要与集群内部的服务通信,不可能把每个服务的url都给记住,这时候,就需要一个服务端反向代理的组件去将外部的请求转发到指定的服务上。说到反向代理就会有人想到了Nginx,但我们不用Nginx做这个事,Netflix为我们提供了Spring Cloud的代理组件 -> Zuul,当然zuul的作用并不只是用来做反向代理,它通常用来做网关

详细代码看 zuul 模块

先来创建个服务提供者 -> zuul-provider,和所有的服务提供者一样,访问 /user-search/test 接口返回 test zuul ok 字符串

@RestController
@RequestMapping("/user-search")
public class UserSearchController {

    @RequestMapping("/test")
    public String list() {
        return "test zuul ok";
    }
}

创建 zuul-server 作为网关服务器

添加依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>

配置

zuul-server application.properties

eureka.client.service-url.defaultZone=http://localhost:8080/eureka
spring.application.name=zuul-server
server.port=8081

# 将 http://localhost:8081/user -> http://localhost:8082/
zuul.routes.user.url=http://localhost:8082

在启动类上加 @EnableZuulProxy 注解

@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy
public class ZuulServer {
    public static void main(String[] args) {
        SpringApplication.run(ZuulServer.class, args);
    }
}

启动Eureka(8080),zuul-server(8081),zuul-provider(8082)
image20200612154039614.png

访问 http://admin-pc:8081/user/user-search/test 发现网关将 /user 开头的请求转发到了 http://localhost:8082
image20200612154150482.png

Zuul路由配置

除了上面说的直接用url配置重定向地址,在集群中我们通常用一个服务ServiceId来表示它的地址

# 配置service-id路由,作用同上
zuul.routes.user.path=/user/**
zuul.routes.user.service-id=zuul-provider

请求/user开头的路径会被转发到zuul-provider这个服务

下面这两种配置效果是一样的,注意,如果指定url的形式,则必须以http或https开头

zuul.routes.user.url=http://localhost:8082
# ==
zuul.routes.user.path=/user/**
zuul.routes.user.service-id=http://localhost:8082

跳转路由

在外部服务访问网关的A地址,就会跳转到B地址

@RestController
public class ForwardTestController {

    @RequestMapping("/test1")
    public String test1() {
        return "test1";
    }
    
    @RequestMapping("/test2")
    public String test2() {
        return "test2";
    }
}

网关配置,path的最后要以 / 结尾,不然404,访问网关的/test1被转发到了/test2

zuul.routes.forwardTest.path=/test1/
zuul.routes.forwardTest.url=forward:/test2

请求 /forward-test/test1 转发到 /forward-test/test2,当然也可以跨服务转发

Zuul使用Ribbon做负载均衡

zuul配置service-id为provider的service-id
两个服务的service-id为ZUUL-PROVIDER,访问/zuul-provider开头的请求走这两个服务,默认是轮询

#zuul.routes.zuulProvider.path=/zuul-provider/**
#zuul.routes.zuulProvider.service-id=ZUUL-PROVIDER
# 上面的简写形式
zuul.routes.ZUUL-PROVIDER.path=/zuul-provider/**

注意:只有以service-id形式指定才能使用ribbon,如果是使用url或者forward,则不会使用ribbon

启动两个服务provider-1(8082),provider-2(8083),zuul(8081),eureka(8080)

image.png

访问两次,返回结果不一样

image.png
image.png

忽略路由

# 忽略该url
zuul.ignored-patterns=/zuul-provider/ignore

java代码

/**
 * 不进行路由的url
 */
@RequestMapping("/ignore")
public String ignore() {
    return "this is ignore url";
}

访问 /zuul-provider/ignore 404
image.png

Zuul请求头配置

过滤请求头

默认情况下,zuul会过滤掉 cookieset-cookieauthorization等请求头,不让他们传递到服务端

/**
 * 过滤header测试
 * <p>
 * 默认情况下 zuul会过滤掉cookie,set-cookie,authorization,它们是不会传递到服务端的
 *
 * haveHeader不在规则之内,是可以传递过来的
 */
@RequestMapping("/header")
public String header(@RequestHeader(value = "cookie", required = false) String cookie,
                     @RequestHeader(value = "set-cookie", required = false) String setCookie,
                     @RequestHeader(value = "authorization", required = false) String authorization,
                     @RequestHeader(value = "haveHeader") String haveHeader
) {
    return String.format("cookie=%s\nset-cookie=%s\nauthorization=%s\nhaveHeader=%s", cookie, setCookie, authorization, haveHeader);
}

image.png

自定义过滤请求头

在zuul配置,只过滤cookie,noHeader

zuul.sensitive-headers=cookie,noHeader
/**
 * 自定义过滤请求头
 */
@RequestMapping("/noHeader")
public String noHeader(@RequestHeader(value = "cookie", required = false) String cookie,
                     @RequestHeader(value = "set-cookie", required = false) String setCookie,
                     @RequestHeader(value = "authorization", required = false) String authorization,
                     @RequestHeader(value = "noHeader", required = false) String noHeader
) {
    return String.format("cookie=%s\nset-cookie=%s\nauthorization=%s\nnoHeader=%s", cookie, setCookie, authorization, noHeader);
}

image.png
可以发现,只有cookie和noHeader被过滤掉了,覆盖了默认配置

Zuul集成Hystrix

在zuul-server添加一个类,继承FallbackProvider

@Component
public class ZuulFackProvider implements FallbackProvider {

    /**
     * 匹配所有service-id,也可以指定service-id,只为改service-id的服务处理降级逻辑
     */
    public String getRoute() {
        return "*";
    }

    public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
        System.err.println("zuul-err");
        return new ClientHttpResponse() {

            public HttpHeaders getHeaders() {
                HttpHeaders httpHeaders = new HttpHeaders();
                httpHeaders.add("Content-Type", "text/html;charset=UTF-8");
                return httpHeaders;
            }

            public InputStream getBody() throws IOException {
                return new ByteArrayInputStream("<h1>zuul error</h1>".getBytes("UTF-8"));
            }

            public HttpStatus getStatusCode() throws IOException {
                return HttpStatus.INTERNAL_SERVER_ERROR;
            }

            public int getRawStatusCode() throws IOException {
                return HttpStatus.INTERNAL_SERVER_ERROR.value();
            }

            public String getStatusText() throws IOException {
                return HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase();
            }

            public void close() {
            }
        };
    }
}

服务端接口,让他3秒内不响应,zuul默认超时时间是2秒

@RequestMapping("/timeout")
public String timeout() throws InterruptedException {
    Thread.sleep(3000);
    return "timeout";
}

可配置zuul访问超时时间

# 超时时间设置,默认是2秒
zuul.host.socket-timeout-millis=2000
zuul.host.connect-timeout-millis=2000
# 光设置zuul的超时时间没用,还需要设置ribbon的超时时间
ribbon.ReadTimeout=2000
ribbon.SocketTimeout=2000

image.png

Zuul预加载Ribbon

通常只有第一次请求服务的时候,zuul才会加载ribbon,通过配置让zuul在启动的时候就初始化好ribbon

zuul.ribbon.eager-load.enabled=true

@EnableZuulServer和@EnableZuulProxy区别

@EnableZuulServer相当于低配版的@EnableZuulProxy,使用@EnableZuulServer之后,SimpleHostRoutingFilter和RibbonRoutingFilter等过滤器就不会被启用。就是说使用@EnableZuulServer的zuul-server就不具备简单路由和负载均衡的能力。


源码:https://codox.coding.net/public/springcloud-learning/springcloud-learning/git/files

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×