Spring cloud分布式系统搭建(六)

六、API网关:Zuul

zuul也叫路由网关,具体啥作用咱目前也不用管,个人喜欢先上手,会用了再去了解它到底是什么。咱们暂时可以参考controller来理解zuul,简单来说就类似于路径带"/order"访问订单服务,带"/goods"访问商品服务。

开干,新建模块zuul,pom.xml如下:

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.mujio</groupId>
    <artifactId>zuul</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>zuul</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <!-- 引入zuul时使用Hoxton.SR3 -->
<!--        <spring-cloud.version>Greenwich.RC2</spring-cloud.version>-->
        <spring-cloud.version>Hoxton.SR3</spring-cloud.version>
    </properties>

    <dependencies>
        <!-- 需要eureka依赖 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <!-- zuul依赖 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

注意:引入zuul时,会发现依赖报错,将spring cloud版本换成Hoxton.SR3可解决。

启动类开启eureka和zuul的注解:

@EnableDiscoveryClient
@EnableZuulProxy

在这里插入图片描述

修改配置文件为application.yml:

server:
  port: 7100

spring:
  application:
    #指定服务名称
    name: zuul-server

eureka:
  client:
    #是否注册到Eureka服务中
    register-with-eureka: true
    #是否从Eureka服务中获取注册信息
    fetch-registry: true
    service-url:
      #Eureka客户端与服务端进行交互的地址
      defaultZone: http://mujio:123456@localhost:7000/eureka/
  instance:
    #把ip地址注册到Eureka服务中
    prefer-ip-address: true
    ip-address: 127.0.0.1


zuul:
  routes:
    goods-server:
      # 将所有/goods/的路径映射到goods-server上
      path: /goods/**
      serviceId: goods-server
      strip-prefix: false

启动,测试http://localhost:7100/goods/1和http://localhost:7100/goods-server/goods/1:在这里插入图片描述

我们访问的是zuul的端口,加上的是商品服务的映射路径,成功获取到商品服务的返回值,但是为什么这两个路径都是正常的呢?大家可以去掉配置文件中的 strip-prefix: false 试试,把path改为其他值再试试。

在zuul实现路由时,还可以通过继承ZuulFilter来实现路由前置后置等方法,且看代码:

package com.mujio.zuul.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.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

/**
 * 可以通过不同的filter继承ZuulFilter来实现前置后置等方法
 * FilterConstants.PRE_TYPE请求被路由前调用
 * FilterConstants.POST_TYPE在ROUTE和ERROR后调用
 * FilterConstants.ROUTE_TYPE请求时调用
 * FilterConstants.ERROR_TYPE请求出现错误时调用
 */
@Component
public class UserFilter extends ZuulFilter{
    
    // 请求被路由前调用
    @Override
    public String filterType() {
        return FilterConstants.PRE_TYPE;
    }

    //数值越大优先级越靠后
    @Override
    public int filterOrder() {
        return 0;
    }
    
    //是否进行过滤
    @Override
    public boolean shouldFilter() {
        return true;
    }
    
    //具体的过滤规则实现
    @Override
    public Object run() throws ZuulException {
        HttpServletRequest req = RequestContext.getCurrentContext().getRequest();
        String token = req.getParameter("token");
        if (StringUtils.isEmpty(token)){
            RequestContext.getCurrentContext().setSendZuulResponse(false);//不进行路由
            RequestContext.getCurrentContext().setResponseStatusCode(200);
            RequestContext.getCurrentContext().setResponseBody("{\"error\":\"invalid token\"}");
        }
        return null;
    }
}

重启,测试http://localhost:7100/goods/1:在这里插入图片描述
http://localhost:7100/goods/1?token=1:在这里插入图片描述

如上效果,通过zuul实现了token验证的功能。

解决上一节提到的两个问题:

  1. eureka服务挂了咋办?
  2. 启动多个订单服务有什么用?

首先看第一个问题,我们先复制两份eureka,端口设为7001、7002。修改三个eureka服务配置文件为:

eureka:

server:
  port: 7000

spring:
  application:
    name: eureka-server
  security:
    user:
      #认证信息
      name: mujio
      password: 123456

eureka:
  client:
    #是否注册到Eureka服务中
    register-with-eureka: true
    #是否从Eureka服务中获取注册信息---修改为true
    fetch-registry: true
    service-url:
      #Eureka客户端与服务端进行交互的地址,加入认证信息---修改为用","隔开的两个eureka地址
      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@localhost:7001/eureka/,http://${spring.security.user.name}:${spring.security.user.password}@localhost:7002/eureka/

eureka01:

server:
  port: 7001

spring:
  application:
    name: eureka-server
  security:
    user:
      #认证信息
      name: mujio
      password: 123456

eureka:
  client:
    #是否注册到Eureka服务中
    register-with-eureka: true
    #是否从Eureka服务中获取注册信息---修改为true
    fetch-registry: true
    service-url:
      #Eureka客户端与服务端进行交互的地址,加入认证信息---修改为用","隔开的两个eureka地址
      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@localhost:7000/eureka/,http://${spring.security.user.name}:${spring.security.user.password}@localhost:7002/eureka/

eureka02:

server:
  port: 7002

spring:
  application:
    name: eureka-server
  security:
    user:
      #认证信息
      name: mujio
      password: 123456

eureka:
  client:
    #是否注册到Eureka服务中
    register-with-eureka: true
    #是否从Eureka服务中获取注册信息---修改为true
    fetch-registry: true
    service-url:
      #Eureka客户端与服务端进行交互的地址,加入认证信息---修改为用","隔开的两个eureka地址
      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@localhost:7000/eureka/,http://${spring.security.user.name}:${spring.security.user.password}@localhost:7001/eureka/

重启,测试http://localhost:9000/order/1:
在这里插入图片描述

停止eureka,再次访问;停止eureka01再次访问;停止eureka02再次访问。再逐次停止goods-server再次访问。

可以发现,eureka服务并没有影响到order服务的运行,但是商品服务的宕机,影响到了order获取商品的信息,直到所有的eureka和商品服务都宕机了,订单服务任然能运行,只是获取不到正确的商品信息。真正实现了订单服务的高可用。

至此,我们的分布式系统已经相对完整了,这个时候我们来考虑第二个问题:

2.订单服务挂了怎么办?

其实这个问题我并没有找到满意的解答。准确的问题中心并不单单指订单服务,可以是登陆中心,可以是Zuul网关等等。

假设用户走进"门店",门店可以通过各种方法保证提供稳定的服务,但是保证门店屹立不倒呢?这个问题还是留着继续思考吧。

下一节,引入config配置中心。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值