JAVA服务器开发Spring Cloud 互联网程序

分布式系统开发---服务网关SpringCloud(十)

2019-01-10  本文已影响0人  Felix_

有几天没有写文章了,新搬的公司感觉味道重,经常头疼,影响进度😂。
言归正传,本节我们引入 路由

路由是微服务架构的不可或缺的一部分,比如我们使用"/" 映射到你应用主页,/goods-service/goods映射到商品服务,/order-service/order映射到订单服务

Spring Cloud中的Zuul不仅可以帮助我们完成路由,还具有认证压力测试金丝雀测试动态路由负载削减安全静态响应处理主动/主动交换管理,同时Zuul的规则引擎允许通过任何JVM语言来编写规则和过滤器。
接下来我们在项目中引入Zuul,首先,创建一个新的模块zuul,在依赖选择里面分别添加Eureka Server


以及Zuul
本节我上传代码到了私有Git仓库,同时更换了MBP作开发,IDE使用了IDEA 2018.3,所以可能看到的图片跟之前的不是太一样,大家仍然按照正常开发就可。

引入完依赖之后,修改ZuulApplication代码

package com.felix.zuul;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;

@EnableDiscoveryClient
@EnableZuulProxy
@SpringBootApplication
public class ZuulApplication {

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

}

这里,我们启用了服务发现@EnableDiscoveryClient,启用了服务网关@EnableZuulProxy。接下来,修改application.propertiesapplication.yml,对服务器做如下配置:

server:
  port: 9000

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

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

zuul:
  routes:
    goods-service:
      path: /goods-service/**
      serviceId: goods-service

这里,把服务网关注册到了服务中心,同时,把所有商品服务相关的接口映射到了goods-service这个服务中,启动如下服务器

1台或多台```服务中心服务器```
1台或多台```商品服务器```
1台```网关服务器```

所有服务器启动之后,访问下http://127.0.0.1:7000/查看服务是否成功注册:


没问题,那么我们首先访问下http://127.0.0.1:8000/goods/2,返回信息如下:

商品信息正常返回,但是异常的确实返回的数据不再是JSON格式的数据,而是XML格式的数据了,这个问题我们之前提到过,解决方案就是在Eureka依赖中排除jackson-dataformat-xml,以下是goods模块中的Eureka依赖修改后的样子:
<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>com.fasterxml.jackson.dataformat</groupId>
                    <artifactId>jackson-dataformat-xml</artifactId>
                </exclusion>
            </exclusions>
</dependency>

修改后重启商品服务器并再次访http://127.0.0.1:8000/goods/2


返回格式已经正常了。为了测试网关的路由是否能够为我们正常提供服务,我们访问http://localhost:9000/goods-service/goods/3

可见,9000端口的服务网关已经能够正常的为我们的服务提供路由转发了。但是,每次访问又要把原本业务的api添加一个goods-service字符串,很麻烦有木有。当然,解决办法是有的,修改zuul模块中的application.yml的zuul配置
server:
  port: 9000

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

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


zuul:
  routes:
    goods-service:
      path: /goods/**
      serviceId: goods-service
      strip-prefix: false

我们把所有跟goods相关的服务映射到商品信息服务上,同时设置strip-prefixfalse,就达到我们的需求了,修改后启动服务器测试下http://localhost:9000/goods/3


这样,我们在不破坏原有接口的前提下,通过9000端口,就可以像访问8000端口的商品信息一样获取信息了。
当然,我们平时还需要它帮我们做一些其他的事情,比如说请求验证、请求预处理等等,接下来,我们就来看下如何实现这些功能。
首先我们需要创建一个继承于ZuulFilter的类,并实现它的四个方法

public String filterType()

  • FilterConstants.PRE_TYPE请求被路由前调用
  • FilterConstants.POST_TYPE在ROUTE和ERROR后调用
  • FilterConstants.ROUTE_TYPE请求时调用
  • FilterConstants.ERROR_TYPE请求出现错误时调用

public int filterOrder()
数值越大优先级越靠后

public boolean shouldFilter()
是否进行过滤

public Object run() throws ZuulException
具体的过滤规则实现
接下来,我们加入自己的逻辑,创建一个UserFilter,对于到来的请求查看是否携带token信息,如果携带了,则认为是已经登录的用户,正常返回数据,否则,不进行路由,返回我们设定好的数据,如下

package com.felix.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;

@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;
    }
}

其中setSendZuulResponse设置为false则不在进行路由,相反,路由按照正常罗技的执行。代码里,我们设定请求中必须携带token信息,如果没有token信息则返回invalid token,启动服务器,我们首先访问http://127.0.0.1:9000/goods/3,由于没有携带token信息,被提示为无效的token信息


然后访问http://127.0.0.1:9000/goods/3?token=123,此时,由于携带了token信息,路由到了商品服务器,正常获得商品信息

截止到现在,分布式系统常用的组件基本介绍完毕了,项目也已经改造的差不多了,有个问题也就凸显了出来,其实我们目前的业务逻辑很少改变,改变的大多数是服务器的配置,随着服务器数量的增多,服务器配置将是一件繁琐的事情,那么,我们怎么样才能让这件事情更简单呢?下节,我们将开始把将服务器的配置工作一步一步的减轻,最终达到在同一个地方修改配置,无需重启服务器,自动同步到所有的服务器中。

以上内容转载请注明出处,同时也请大家不吝你的关注和下面的赞赏
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

上一篇下一篇

猜你喜欢

热点阅读