1,网关服务存在要求
原因:
首先,传统没有网关的架构中,需要运维人工维护路由规则和服务实例,增大了人工维护成本和效率低下。
其次,在系统中,我们往往需要有一定的权限校验机制,但是当微服务系统多的话,就会增加开发人员和测试的工作量。代码冗余。
网关的解决:
首先,对于路由规则与服务实例的维护问题,Zuul通过与Eureka进行整合,将自身注册在Eureka中,获取所有其他微服务的实例信息,自动的维护服务实例,而对于路由规则,Zuul默认会将通过以服务名作为ContextPath的方式来创建路由映射。
其次,对于类似签名检验,登录检验的冗余问题,Zuul提供了一套过滤器机制,将非业务的东西抽离出来。
2,搭建Zuul
新建一个springboot项目,修改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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.gateway</groupId>
<artifactId>gateway</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>gateway</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Dalston.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
修改主类的注解
package com.gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.cloud.client.SpringCloudApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.context.annotation.Bean;
@EnableZuulProxy
@SpringCloudApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
@Bean
public AccessFilter accessFilter(){
return new AccessFilter();
}
}
然后配置文件中
spring.application.name=gateway-service //服务名称
server.port=5555 //服务端口
eureka.client.serviceUrl.defaultZone=http://127.0.0.1:8000/eureka/ //Eureka注册中心地址
eureka.instance.preferIpAddress=true
zuul.routes.ribbon-service.path=/ribbon-service/** //需要通过网关的实例服务路由
zuul.routes.ribbon-service.serviceId=ribbon-service //需要通过网关的实例服务
zuul.routes.feign-service.path=/feign-service/**
zuul.routes.feign-service.serviceId=feign-service
zuul.routes.hello-service.path=/hello-service/**
zuul.routes.hello-service.serviceId=hello-service
到这里就基本完成了,启动项目,可以在Eureka中看到有网关服务的实例了
通过访问网关服务的端口和实例服务的名称可以转发到实际的实例服务中,比如:http://127.0.0.1:5555/hello-service/hello
在启动类中我加了AccessFilter这个Bean,这是添加了过滤器
package com.gateway;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.http.HttpServletRequest;
/**
* Created by qhe on 2018/7/31.
*/
public class AccessFilter extends ZuulFilter {
private static Logger logger = LoggerFactory.getLogger(AccessFilter.class);
@Override
public String filterType() {
return "pre";
}
@Override
public int filterOrder() {
return 0;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
logger.info("send{}request to {}",request.getMethod(),request.getRequestURL().toString());
Object accessToken = request.getParameter("accessToken");
if(accessToken == null){
logger.warn("accessToken is empty");
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(401);
return null;
}
logger.info("accessToken is ok");
return null;
}
}
通过继承ZuulFilter,有四个方法:
filterType:过滤器类型,这里返回的是Pre表示所有的都过滤
filterOrder:过滤器顺序
shouldFilter:判断该过滤器是否需要被执行,返回true或false。
run():过滤器具体的逻辑。
通过加上过滤器,我们再访问:http://127.0.0.1:5555/hello-service/hello,会返回401.