微服务架构学习-进阶篇--07,服务网关(下)

第六节,采用网关过滤对系统异常统一处理

(1)在zuul模块下新建maven项目,命名为zuul-gateway-filter-exception。
(2)pom文件添加依赖。
(3)配置文件添加配置。
(4)添加一个启动类。
然后是各种过滤器的实践:
(5)先新建一个权限校验的过滤器,如下:

package com.twf.zuul.gateway.filter.exception.filter;

import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;

@Component
public class AccessFilter extends ZuulFilter{

	private static final Logger logger = LoggerFactory.getLogger(AccessFilter.class);
	
	/**
	 * 是否开启过滤器,默认为false,不开启。我们现在开启它,就设为true。
	 */
	@Override
	public boolean shouldFilter() {
		return true;
	}

	/**
	 * 过滤器的作用,权限校验
	 */
	@Override
	public Object run() {
		RequestContext rc=RequestContext.getCurrentContext();
		HttpServletRequest request=rc.getRequest();
		logger.info("---------------------------pre1-------------------------------");
		String token = request.getParameter("token");
		if (token == null) {
			logger.warn("token is  null...............");
			rc.setSendZuulResponse(false); // false代表结束请求,不再继续下级传递
			rc.setResponseStatusCode(401);
			rc.setResponseBody("{\"result\":\"token is null\"}");
			rc.getResponse().setContentType("text/html;charset=utf-8");
		} else {
			logger.info("token is ok");
			
		}
		return null;
	}

	@Override
	public String filterType() {
		return "pre";
	}

	/**
	 * 控制执行顺序
	 */
	@Override
	public int filterOrder() {
		return 0;
	}
}

启动该项目和ProductCoreApplication,浏览器访问http://localhost:8118/e-book-product/product/findAllProduct,界面如下:
在这里插入图片描述
然后,我们再访问http://localhost:8118/e-book-product/product/findAllProduct?token=aaa,数据就能正常出来了。
(6)下面测试一下过滤器的执行顺序,复制AccessFilter.java,重命名为TestPreFilter,修改代码如下:

package com.twf.zuul.gateway.filter.exception.filter;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
/**
 * 这个类的目的就是为了验证filterOrder的顺序
 * @author twf
 *
 */
@Component
public class TestPreFilter extends ZuulFilter{
	private static final Logger logger = LoggerFactory.getLogger(TestPreFilter.class);
	
	/**
	 * 是否开启过滤器,默认为false,不开启。我们现在开启它,就设为true。
	 */
	@Override
	public boolean shouldFilter() {
		return true;
	}
	/**
	 * 过滤器的作用,权限校验
	 */
	@Override
	public Object run() {
		RequestContext rc=RequestContext.getCurrentContext();
		HttpServletRequest request=rc.getRequest();
		logger.info("---------------------------pre2-------------------------------");
		return null;
	}
	@Override
	public String filterType() {
		return "pre";
	}
	@Override
	public int filterOrder() {
		return 1;
	}
}

然后浏览器访问http://localhost:8118/e-book-product/product/findAllProduct?token=aaa,后台打印如下:
在这里插入图片描述
出现这个顺序,说明,filterOrder()方法返回的值越小,越先被执行。
(7)测试过滤器的post类型,复制AccessFilter.java,重命名为PostFilter.java,修改代码如下:

package com.twf.zuul.gateway.filter.exception.filter;

import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;

@Component
public class PostFilter extends ZuulFilter{

	private static final Logger logger = LoggerFactory.getLogger(PostFilter.class);
	
	/**
	 * 是否开启过滤器,默认为false,不开启。我们现在开启它,就设为true。
	 */
	@Override
	public boolean shouldFilter() {
		return true;
	}

	/**
	 * 过滤器的作用
	 */
	@Override
	public Object run() {
		RequestContext rc=RequestContext.getCurrentContext();
		HttpServletRequest request=rc.getRequest();
		logger.info("---------------------------post-------------------------------");
		return null;
	}

	@Override
	public String filterType() {
		return "post";  // 这里一定要改为post
	}

	/**
	 * 控制执行顺序
	 */
	@Override
	public int filterOrder() {
		return 0;
	}
}

浏览器访问http://localhost:8118/e-book-product/product/findAllProduct?token=aaa,后台打印如下:
在这里插入图片描述
从上图可以看出,post类型的过滤器在pre类型过滤器的后面执行。
(8)测试过滤器的error类型,复制PostFilter,重命名为ErrorFilter,修改代码如下:

package com.twf.zuul.gateway.filter.exception.filter;

import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;

@Component
public class ErrorFilter extends ZuulFilter{

	private static final Logger logger = LoggerFactory.getLogger(ErrorFilter.class);
	
	/**
	 * 是否开启过滤器,默认为false,不开启。我们现在开启它,就设为true。
	 */
	@Override
	public boolean shouldFilter() {
		return true;
	}

	/**
	 * 过滤器的作用,权限校验
	 */
	@Override
	public Object run() {
		RequestContext rc=RequestContext.getCurrentContext();
		HttpServletRequest request=rc.getRequest();
		logger.info("---------------------------error-------------------------------");
		return null;
	}

	@Override
	public String filterType() {
		return "error";
	}

	/**
	 * 控制执行顺序
	 */
	@Override
	public int filterOrder() {
		return 0;
	}
}

启动,浏览器访问http://localhost:8118/e-book-product/product/findAllProduct?token=aaa,后台打印如下:
在这里插入图片描述
(9)加一个类,铺获异常,代码如下。

package com.twf.zuul.gateway.filter.exception.filter;

import org.springframework.boot.autoconfigure.web.ErrorController;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 异常的统一捕获类
 * @author twf
 *
 */
@RestController
public class ErrorGatewayController implements ErrorController{

	@Override
	public String getErrorPath() {
		return "/error";
	}
	
	@RequestMapping("/error")
	public String error() {
		return "{\"result\":\"500 error!!!\"}";
	}
}

重启服务,访问http://localhost:8118/e-book-product/product/findAllProduct?token=aaa,界面如下:
在这里插入图片描述

第七节,网关容错:zuul和hystrix无缝结合

zuul天生就集成了hystrix,我们不需要做额外的操作去结合它们。
(1)我们启动ZuulFilterException,ProductCoreApplication,e-book-consumer-hystrix-dashboard这三个服务。
(2)浏览器访问http://localhost:8118/e-book-product/product/findAllProduct?token=aaa,界面如下:
在这里插入图片描述
(3)浏览器访问http://localhost:8118/hystrix.stream,界面如下:
在这里插入图片描述
(4)浏览器访问http://localhost:8107/hystrix,界面如下:
在这里插入图片描述
输入http://localhost:8118/hystrix.stream,点“Monitor Stream”,界面如下:
在这里插入图片描述

第八节,网关容错:网关如何实现服务降级

我们已经学过ribbon的服务降级,feign的服务降级,现在来看看网关的服务降级。
(1)在zuul模块下新建maven项目,命名为zuul-gateway-fallback,
(2)修改配置文件,加入相应依赖;
(3)添加一个配置文件,加入相应的配置;
(4)添加一个启动类;
(5)添加一个provider,代码如下:

package com.twf.zuul.gateway.fallback.fallback;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;

import org.springframework.cloud.netflix.zuul.filters.route.ZuulFallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;

@Component
public class ProductFallbackProvider implements ZuulFallbackProvider {

	/**
	 * 代表为哪个服务提供fallback,这里我们为e-book-product这个服务提供fallback
	 */
	@Override
	public String getRoute() {
		return "e-book-product";
	}

	@Override
	public ClientHttpResponse fallbackResponse() {
		return new ClientHttpResponse() {

			@Override
			public InputStream getBody() throws IOException {
				String input = "商品服务不可用,请联系管理员!";
				return new ByteArrayInputStream(input.getBytes());
			}

			@Override
			public HttpHeaders getHeaders() {
				HttpHeaders header = new HttpHeaders();
				MediaType mt = new MediaType("application","json",Charset.forName("UTF-8"));
				header.setContentType(mt);
				return header;
			}

			@Override
			public HttpStatus getStatusCode() throws IOException {
				// httpresponse的fallback的状态码,HttpStatus值
				return HttpStatus.OK;
			}

			@Override
			public int getRawStatusCode() throws IOException {
				// httpresponse的fallback的状态码,int值
				return this.getStatusCode().value();
			}

			@Override
			public String getStatusText() throws IOException {
				// httpresponse的fallback的状态码,String值
				return this.getStatusCode().getReasonPhrase();
			}

			@Override
			public void close() {
				
			}};
	}
}

(6)启动该项目及ProductCoreApplication,浏览器访问http://localhost:8119/e-book-product/product/findAllProduct,界面如下:
在这里插入图片描述
(7)停掉ProductCoreApplication,再访问,出现如下结果:
在这里插入图片描述
说明降级操作成功。

第九节,在高并发的情况下,网关如何实现限流达到自我保护

(1)在zuul模块下新建maven项目,命名为zuul-gateway-ratelimit。
(2)修改pom文件,加入如下依赖:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>

<dependency>
	<groupId>com.marcosbarbero.cloud</groupId>
	<artifactId>spring-cloud-zuul-ratelimit</artifactId>
	<version>1.3.4.RELEASE</version>
</dependency>

(3)修改配置文件,配置如下:

spring.application.name=zuul-gateway
server.port=8120

eureka.client.serviceUrl.defaultZone=http://user:123456@eureka1:8761/eureka/,http://user:123456@eureka2:8762/eureka/

zuul.routes.book-product.path=/book-product/**
zuul.routes.book-product.serviceId=e-book-product

#开启限流
zuul.ratelimit.enabled=true
#60s内请求超时3次,服务端就抛出异常,60s后可以恢复正常请求
zuul.ratelimit.policies.book-product.limit=3
zuul.ratelimit.policies.book-product.refresh-interval=60
#针对某个IP进行限流,不影响其他IP
zuul.ratelimit.policies.book-product.type=origin

(4)添加一个启动类。
(5)启动该项目,和ProductCoreApplication。
(6)浏览器访问http://localhost:8120/book-product/product/findAllProduct,界面如下:
在这里插入图片描述
然后在刷新几次,就变成下面这样了:
在这里插入图片描述
后台也报如下异常:
在这里插入图片描述
(7)网关限流参数说明。
在这里插入图片描述
(8)修改配置文件,注释掉某一个服务的局部配置,添加限流的全局配置。

spring.application.name=zuul-gateway
server.port=8120

eureka.client.serviceUrl.defaultZone=http://user:123456@eureka1:8761/eureka/,http://user:123456@eureka2:8762/eureka/

#----------------------------针对某个服务进行限流--------------------------
#zuul.routes.book-product.path=/book-product/**
#zuul.routes.book-product.serviceId=e-book-product

#开启限流
#zuul.ratelimit.enabled=true
##60s内请求超时3次,服务端就抛出异常,60s后可以恢复正常请求
#zuul.ratelimit.policies.book-product.limit=3
#zuul.ratelimit.policies.book-product.refresh-interval=60
##针对某个IP进行限流,不影响其他IP
#zuul.ratelimit.policies.book-product.type=origin

#---------------------------------针对所有服务进行限流------------------------
#加全局配置
zuul.ratelimit.enabled=true
zuul.ratelimit.default-policy.limit=3
zuul.ratelimit.default-policy.refresh-interval=60
zuul.ratelimit.default-policy.type=origin

(9)浏览器访问http://localhost:8120/e-book-product/product/findAllProduct,结果也是前3次访问正常,之后就不能访问了,错误同上。

第十节,zuul性能调优

(1)在zuul模块下新建maven项目,命名为zuul-gateway-timeout。
(2)修改pom文件,加入相应依赖。
(3)添加一个配置文件,配置如下:

spring.application.name=zuul-gateway
server.port=8121

eureka.client.serviceUrl.defaultZone=http://user:123456@eureka1:8761/eureka/,http://user:123456@eureka2:8762/eureka/

(4)添加一个启动类。
(5)修改e-book-product-core:
在这里插入图片描述
(6)浏览器访问http://localhost:8121/e-book-product/product/findAllProduct,界面如下:
在这里插入图片描述

无论刷新多少次,都不能访问成功。这是因为,zuul底层采用了ribbon和hystrix来通信,hystrix的超时时间为1s,而我们接口休眠了2s,这样网关永远都不能访问这个接口了,原理图如下:
在这里插入图片描述
(7)改造配置文件,加入如下配置,对zuul进行性能调优。

#第一层hystrix超时时间设置
#默认情况下是线程池隔离,超时时间为1000ms
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=8000

#第二层ribbon超时时间设置,设置比第一层小
# 请求连接的超时时间:默认5s
ribbon.ConnectTimeout=5000
#请求处理的超时时间:默认5s
ribbon.ReadTimeout=5000

(8)重启该服务,重新访问,数据正常了。
源码点这里

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值