为什么要使用网关?
如果服务搭建集群的话,每个端口都不同,那么前端进行访问的时候到底访问哪个呢?
在微服务项目中,访问服务是需要验证是否登录的,比如支付服务之类的,如果每个服务都写一套验证的代码的话就会很重复,这时候就可以使用网关统一管理服务,客户端先访问网关,然后再转发到具体的服务上去,还有就是有的服务避免被直接访问,都是以内网的方式进行存在的,只能在项目中同一局域网进行访问,就可以使用暴露外网的网关统一管理服务作为统一入口.
网关可以拦截客户端所有请求,对该请求进行权限控制,负载均衡,日志管理,接口调用监控等.
过滤器是拦截单个tomcat的请求的,网关是拦截整个微服务的所有请求的,
Nginx与Zuul的区别
相同点是都可以实现负载均衡,反向代理,过滤请求,实现网关效果.
不同点:Nginx采用C语言编写的Zuul采用java语言编写的
Zuul负载均衡实现采用ribbon+eureka实现本地负载均衡.
Nginx负载均衡实现采用服务端负载均衡
Nginx比Zuul功能更加强大,因为Nginx整合一些脚本语言(Nginx+Lua)
Nginx适合于服务器端负载均衡,也可以实现网关
Zuul适合微服务中实现网关,而且使用技术是java语言.
比如下面的一个例子,要在网关中实现对服务进行验证是否登录,如果使用Nginx当网关的话,实现起来非常麻烦,毕竟不是java语言写的.这就是区别,zuul是管理微服务项目中服务的,Nginx是管理这些统一入口集群的
可以使用nginx+zuul实现网关 nginx作用实现反向代理,zuul对服务实现网关拦截.
搭建网关
这个网关也是注册到eureka上的,所有在搭建网关前先搭建eureka服务端,和member,order两个客户端.https://blog.csdn.net/kxj19980524/article/details/86774671
搭建网关服务
<?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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.buba</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.RELEASE</spring-cloud.version>
</properties>
<dependencies>
<!--整合zuul网关-->
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-zuul -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<!--Finchley.RELEASE 加上这个东西,别使用默认的 或者使用Finchley.M7这个兼容springcloud2.0版本但是我使用不好使-->
<version>Finchley.RELEASE</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>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<!--加上这个false就不从上面这个链接里下载jar包-->
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
</project>
###服务注册到eureka地址
eureka.client.service-url.defaultZone=http://localhost:8100/eureka
server.port=80
#注册到eureka上的服务名称
spring.application.name=service-zuul
##这个是访问member服务的路径 api-member这段可以随意起名字
zuul.routes.api-member.path=/member/**
##这个是member注册到eureka的服务名称
zuul.routes.api-member.serviceId=app-buba-member
##这个是访问order服务的路径
zuul.routes.api-order.path=/order/**
##这个是order服务注册到eureka的服务名称
zuul.routes.api-order.serviceId=app-buba-order
然后先启动eureka服务端,再启动网关,再启动member和order服务
然后再写一个过滤器实现统一验证是否登录
package com.buba.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.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
@Component
public class TokenFilter extends ZuulFilter {
public Object run() throws ZuulException {
// 获取上下文
RequestContext currentContext = RequestContext.getCurrentContext();
//获取HttpServletRequest
HttpServletRequest request = currentContext.getRequest();
//从请求头中获取Token信息
String userToken = request.getParameter("userToken");
if (StringUtils.isEmpty(userToken)) {
//设置为false就不会继续执行服务代码了
currentContext.setSendZuulResponse(false);
//设置状态码
currentContext.setResponseStatusCode(401);
//设置相应信息
currentContext.setResponseBody("userToken is null");
return null;
}
// 否则正常执行业务逻辑.....
return null;
}
// 判断过滤器是否生效
public boolean shouldFilter() {
return true;
}
// 过滤器的执行顺序。当请求在一个阶段的时候存在多个多个过滤器时,需要根据该方法的返回值依次执行
public int filterOrder() {
return 0;
}
// 过滤器类型 pre 表示在 请求之前进行拦截
public String filterType() {
return "pre";
}
}