sringcloud2.0学习-16- springcloud微服务网关+Zuul网关搭建

springcloud微服务网关

主要内容:

  • 微服务网关技术产生背景
  • 微服务网关设计思想
  • 微服务网关作用
  • 网关与过滤器的区别
  • spring cloud zuul网关与Nginx的区别
  • 搭建Zuul网关服务器
  • Zuul网关拦截器配置
  • 通过springcloud config分布式配置中心搭建Zuul 动态网关

1.微服务网关技术缘何而来

   这个话题还得从接口说起。传统的三层架构的项目,所有业务都在一个工程里面,比如一个项目里面包含了用户管理业务代码,订单业务的代码,支付业务的代码,这三块仅仅是作为一个项目的三个不同的模块存在, 而分布式微服务项目,为了减轻模块之间的耦合程度,上述三个模块都将变成三个独立的项目,比如用户要购物,要下单,首先得获取用户信息,这时订单服务就需要调用用户服务的相关接口获取用户信息( 这个过程一般是RPC调用 ,也就是接口是在RPC调用中产生的),或者有时候有别的公司要调用这个微服务系统中的接口,等等类似这样不同项目之间的接口调用,不能简简单单的直接去调用,考虑到数据的安全性,幂等性,接口的权限,我们需要在接口请求被处理之前,对这个接口请求的有效性做一个校验。有人说了,这个校验可以写在过滤器里面,没错,但是如果有十个项目都调用同一个接口,岂不是校验逻辑要重复写10遍?这种情况下,一个叫做微服务网关的东西出现了。 一般情况下,微服务项目都是存在于同一个内网系统中,比如,一个微服务系统,包含了用户,订单,支付项目,外面来的接口想要调用这三个项目的接口,都先得关在“小黑屋”经过一番验证,验证过了,才能去调用接口。这个小黑屋,就是网关。

  • 接口分类

开放接口:
   第三方机构(如微信开放平台) 的接口要被调用(必须在外网访问) ,需要通过appid + appsecret 生成accessToken进行通讯,类似这样对外开放,用于被其他外部接口接口调用的接口就是开放接口。
内部接口:
   只能在局域网中访问的接口,服务与服务之间都在同一个微服务系统中,保证系统安全

2.网关作用

  • 网关概念:
    相当于客户端请求统一先请求到网关服务器,再由网关服务器转发到实际服务器地址上,类似于Nginx
  • 网关作用:
    网关可以拦截客户端所有请求,对请求进行权限控制,负载均衡,日志管理,接口调用监控等,如图:
    sringcloud2.0学习-16- springcloud微服务网关+Zuul网关搭建_第1张图片
    zuul网关与Nginx区别:
  • Nginx是采用服务器负载均衡进行转发
  • Zuul依赖Ribbon和eureka实现本地负载均衡转发

相对来说Nginx功能比Zuul功能更加强大,能够整合其他语言比如lua脚本实现强大的功能,同时Nginx可以更好的抗高并发,Zuul网关适用于请求过滤和拦截等。

相同点:Zuul和Nginx都可以实现负载均衡,反向代理,过滤请求,实现网关效果
不同点:
(1)开发语言:Nginx采用C语言编写,效率更高,zuul采用Java编写,
(2)负载均衡实现:
zuul的负载均衡实现采用ribbon+eureka实现负载本地负载均衡
Nginx的负载均衡是服务器端实现负载均衡
(3) Nginx比Zuul功能会更强大,Nginx可以整合一些脚本语言如Lua,Nginx适合于服务器端负载均衡,反向代理;
Zuul适合微服务中实现网关,对微服务实现网关拦截,而且使用技术是Java语言 建议使用nginx+zuul实现网关 (nginx+zuul 可以实现网关集群)

3.过滤器与网关的区别

过滤器拦截单个tomcat服务器的请求,网关是拦截整个微服务系统的所有请求

4. 网关分类

网关分内网网关和外网网关,外网网关是专门针对于开放平台接口的,比如一些合作平台要调用接口时,就通过外网网关进行调用,内网网关是整个微服务内部之间接口相互调用的网关。

5. 网关框架

Netflix Zuul,zuul是spring cloud的一个推荐组件,https://github.com/Netflix/zuul

6.Zuul搭建API网关,实现zuul反向代理和负载均衡

sringcloud2.0学习-16- springcloud微服务网关+Zuul网关搭建_第2张图片
搭建一个项目springcloud2.0-zuul-apigateway

  • pom
    引入spring-cloud-starter-netflix-zuul 网关依赖和eureka客户端依赖
<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.0modelVersion>
	<groupId>com.lchtestgroupId>
	<artifactId>springcloud2.0-zuul-apigatewayartifactId>
	<version>0.0.1-SNAPSHOTversion>
	<parent>
		<groupId>org.springframework.bootgroupId>
		<artifactId>spring-boot-starter-parentartifactId>
		<version>2.0.3.RELEASEversion>
	parent>
	
	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloudgroupId>
				<artifactId>spring-cloud-dependenciesartifactId>
				<version>Finchley.RELEASEversion>
				<type>pomtype>
				<scope>importscope>
			dependency>
		dependencies>
	dependencyManagement>
	<dependencies>
	    
		<dependency>
			<groupId>org.springframework.cloudgroupId>
			<artifactId>spring-cloud-starter-netflix-zuulartifactId>
		dependency>
		
		<dependency>
			<groupId>org.springframework.cloudgroupId>
			<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
		dependency>
	dependencies>
project>
  • 网关配置:
#注册中心
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8100/eureka/
#网关端口
server:
  port: 80
#网关在注册中心的名称
spring:
  application:
    name: service-zuul

#配置网关反向代理(搭建zuul动态网关,下面这个配置放到git上(网关作为configclient从configserver读取git上的配置)然后开启所有监控中心接口)    
zuul:
  #定义转发服务的规则(路由规则)
  routes:
    api-a:   # api-a这里可以随便命名
      #以 /api-member/开头的接口请求转发到会员服务
      path: /api-member/**
      #serviceId是会员服务别名
      serviceId: app-member
      #问题:如果会员服务做了集群,如何转发? zuul网关默认整合了ribbon,自动实现负载均衡轮询效果!
    api-b:
      #客户端请求以127.0.0.1:80/api-order/开头的接口请求转发到订单服务
      path: /api-order/**
      #订单服务别名
      serviceId: app-order
  • 主启动类:
    注解@EnableZuulProxy 开启网关代理!
package com.lchtest;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;

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

启动eureka注册中心,网关服务,member服务,order服务,进行测试

  • 网关实现接口反向代理

直接访问服务: http://localhost:8001/ http://localhost:8005/
通过网关转发接口请求到服务:
http://localhost/api-member 以api-member开头的请求,全部被转发到member服务中了
http://localhost/api-order 以api-order开头的请求,全部被转发到order服务中了
sringcloud2.0学习-16- springcloud微服务网关+Zuul网关搭建_第3张图片

  • Zuul网关实现负载均衡

修改member服务的配置文件中的端口号,再启动一个member服务,这时再通过网关去请求member接口
sringcloud2.0学习-16- springcloud微服务网关+Zuul网关搭建_第4张图片
负载均衡效果如下:
sringcloud2.0学习-16- springcloud微服务网关+Zuul网关搭建_第5张图片

zuul网关实现负载均衡的原理: zuul网关根据配置文件中定义的路由转发规则(如下),对/api-member/**这样的接口请求,去注册中心找注册名为 app-member的服务 ,获取这个服务的实际服务器地址信息,然后再由网关实现本地负载均衡,转发请求到真实的服务器。

zuul:
  #定义转发服务的规则(路由规则)
  routes:
    api-a:   
      #以 /api-member/开头的接口请求转发到会员服务
      path: /api-member/**
      #serviceId是会员服务别名
      serviceId: app-member

在这里插入图片描述

7.网关过滤器

现在假设有这么一个场景,客户端访问member服务或者order服务时,要求校验token信息,如果不包含token,直接拒绝访问,如果保护token信息,就把请求转发到对应服务

  • 创建一个网关过滤器类,校验接口请求是否包含token
package com.lchtest.filter;

import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Component;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
/**
 * 网关服务过滤器
 * @author pc
 * @Component注解,将@Component注入到spring容器
 */
@Component
public class TokenFilter extends ZuulFilter{
	
	/**
	 * 过滤器类型
	 * pre:可以在请求被路由之前调用
	   routing:在路由请求时候被调用
	   post:在routing和error过滤器之后被调用
	   error:处理请求时发生错误时被调用
	 */
	private static final String FILTE_RTYPE = "pre";
	
	/**
	 * 过滤器是否生效
	 */
	private static final boolean SHOULD_FILTER_EFFECTIVE  = true;
	
	/**
	 * 接口鉴权失败
	 */
	private static final int UNAUTHORIZED = 401;

	/**
	 * 判断过滤器是否生效
	 */
	public boolean shouldFilter() {
		return SHOULD_FILTER_EFFECTIVE;
	}

	/**
	 * 过滤器业务逻辑
	 */
	public Object run() throws ZuulException {
		//拦截所有服务接口,判断服务接口上是否有传递userToken参数
		//1.获取上下文
		RequestContext currentContext = RequestContext.getCurrentContext();
		
		//2.获取request对象
		HttpServletRequest request = currentContext.getRequest();
		
		//3.获取token token一般都放在请求头里面发送请求,因此获取token也是从请求头里面获取
//		String token = request.getHeader("token");
		// 这里模拟从请求参数中获取token
		String token = request.getParameter("userToken");
		
		if(StringUtils.isEmpty(token)) {
			// 不往下执行,由网关服务直接响应客户端
			currentContext.setSendZuulResponse(false);
			// 返回错误提示
			currentContext.setResponseBody("userToken is missed.");
			currentContext.setResponseStatusCode(UNAUTHORIZED);
			return null;
		} 
		
		// 接口鉴权通过,正常调用其他服务接口
		return null;
	}

	/**
	 * 过滤器类型:
	 * pre:在请求处理之前执行
	 */
	@Override
	public String filterType() {
		return FILTE_RTYPE;
	}

	/**
	 * 过滤器的执行顺序(优先级)
	 * 一个请求在同一阶段存在多个过滤器的时候,存在过滤器的执行顺序
	 */
	@Override
	public int filterOrder() {
		return 0;
	}
}

重启网关服务,通过网关访问order服务,不带userToken参数时,请求直接被网关拦截并返回401,带上token参数,能够正确访问到order服务
sringcloud2.0学习-16- springcloud微服务网关+Zuul网关搭建_第6张图片
代码地址
使用到的项目:
springcloud2.0-zuul-apigateway
springcloud2.0-eureak-server(单注册中心)
springcloud2.0-feign-parent( order服务, member服务)

你可能感兴趣的:(SpringCloud2.0)