springcloud服务网关讲解

在我的上一篇博客中讲解了什么是网关,网关可以做什么,以及路由和过滤器的类型。如果大家感兴趣的话可以看下springcloud服务网关详细讲解

然后这篇文章主要讲解网关过滤器对系统异常统一处理,zuul和hystrix结合,网关实现服务降级,实现限流等内容。

网关过滤器对系统异常统一处理

目录结构:
在这里插入图片描述
在这个项目中我们不仅做了异常处理还做了权限验证和post验证。
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>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>

配置文件中的代码:

spring.application.name=zull-gateway
server.port=9010
eureka.client.serviceUrl.defaultZone=http://user:test@eureka2:8762/eureka/,http://user:test@eureka1:8761/eureka/
eureka.instance.perferIpAddress=true
ribbon.ReadTimeout=60000
ribbon.ConnectTimeout=60000

ZuulApplication代码:

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

AccessFilter进行权限验证,代码

@Component
public class AccessFilter extends ZuulFilter {
	private static final Logger logger = LoggerFactory.getLogger(AccessFilter.class);
	@Override
	public Object run() throws ZuulException {
		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); //代表结束请求,不再继续下级传递
			rc.setResponseStatusCode(401);
			rc.setResponseBody("{\"result\":\"token is null\"}");
			rc.getResponse().setContentType("text/html;charset=utf-8");
		}else {
//			TODO redis 验证
			logger.info("token is OK");
		}
		return null;
	}
	@Override
	public boolean shouldFilter() {
		return true;
	}
	@Override
	public int filterOrder() {
		// TODO Auto-generated method stub
		return 0;
	}
	@Override
	public String filterType() {
		return "pre";
	}
}

启动product和项目,测试结果:
在这里插入图片描述
在这里插入图片描述
携带token的就可以访问。
验证filterOrder的顺序:
filterOrder的数字越小级别就越高。TestPreFilter代码:

@Component
public class TestPreFilter extends ZuulFilter {
	private static final Logger logger = LoggerFactory.getLogger(TestPreFilter.class);
	@Override
	public Object run() throws ZuulException {
		RequestContext rc = RequestContext.getCurrentContext();
		HttpServletRequest request = rc.getRequest();
		logger.info("------------------pre2--------------------");
//		throw new RuntimeException("error");
		return null;
	}
	@Override
	public boolean shouldFilter() {
		return true;
	}
	@Override
	public int filterOrder() {
		// TODO Auto-generated method stub
		return 1;
	}
	@Override
	public String filterType() {
		return "pre";
	}
}

测试结果:
在这里插入图片描述
TestPreFilter中为1,AccessFilter 为0,说明验证成功。
post验证
PostFilter代码:

@Component
public class PostFilter extends ZuulFilter {
	private static final Logger logger = LoggerFactory.getLogger(PostFilter.class);
	@Override
	public Object run() throws ZuulException {
		RequestContext rc = RequestContext.getCurrentContext();
		HttpServletRequest request = rc.getRequest();
		logger.info("------------------post--------------------");
		
		return null;
	}
	@Override
	public boolean shouldFilter() {
		return true;
	}
	@Override
	public int filterOrder() {
		// TODO Auto-generated method stub
		return 0;
	}
	@Override
	public String filterType() {
		return "post";
	}
}

启动项目测试结果:
在这里插入图片描述
验证成功。
异常处理
ErrorFilter代码:

@Component
public class ErrorFilter extends ZuulFilter {	
	private static final Logger logger = LoggerFactory.getLogger(ErrorFilter.class);
	@Override
	public Object run() throws ZuulException {
		RequestContext rc = RequestContext.getCurrentContext();
		HttpServletRequest request = rc.getRequest();
		logger.info("------------------error--------------------");
		return null;
	}
	@Override
	public boolean shouldFilter() {
		return true;
	}
	@Override
	public int filterOrder() {
		return 0;
	}
	@Override
	public String filterType() {
		return "error";
	}
}

在TestPreFilter中抛出一个异常throw new RuntimeException(“error”);测试:
测试结果:
在这里插入图片描述
先是error再是post。因为出现异常过后会被error接收,然后还会返回给客户端,所以再是post然后再返回给客户。
出现这种异常我们要加入一个异常处理类ErrorGatewayController。
ErrorGatewayController代码:

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

测试结果:
在这里插入图片描述
因为异常已经被我们拦截,所以出现500错误。

网关实现服务降级

zuul和hystrix可以无缝结合,启动一个zuul和product和dashboard。就可以参照springcloud数据监控进行结合。
网关服务降级的目录结构:
在这里插入图片描述
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>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>

配置文件代码:

spring.application.name=zull-gateway
server.port=9010
eureka.client.serviceUrl.defaultZone=http://user:test@eureka2:8762/eureka/,http://user:test@eureka1:8761/eureka/
eureka.instance.perferIpAddress=true

ZuulApplication代码:

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

ProductFallbackProvider代码:

@Component
public class ProductFallbackProvider implements ZuulFallbackProvider{
	@Override
	public String getRoute() {
		//  代表为哪个服务提供fallback
		return "e-book-product";
	}
	@Override
	public ClientHttpResponse fallbackResponse() {
		return new ClientHttpResponse() {
			@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 InputStream getBody() throws IOException {
				String input = "商品服务不可以用,请联系管理员!";
				return new ByteArrayInputStream(input.getBytes());
			}
			@Override
			public String getStatusText() throws IOException {
				// httpresponse的fallback的状态码,string
				return this.getStatusCode().getReasonPhrase();
			}
			@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 void close() {
			}
		};
	}
}

代码中都有方法如何运用的详细注释,启动product和zuul项目进行测试:
在这里插入图片描述
关闭product服务测试:
在这里插入图片描述
这就是网关的降级服务。

网关限流

在高并发下,如果一个IP请求多次就可以对它进行限流,在某个时间内不能访问,然后超过某个时间又可以访问。
项目的目录结构:
在这里插入图片描述
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>

配置 文件中的代码:

spring.application.name=zull-gateway
#配置自定义端口
server.port=9010
#指定一个注册中心
eureka.client.serviceUrl.defaultZone=http://user:test@eureka2:8762/eureka/,http://user:test@eureka1:8761/eureka/
#默认是hostname 注册,改成IP 注册
eureka.instance.perferIpAddress=true
# 针对某个服务进行限流
#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

ZuulApplication代码:

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

在这里插入图片描述
启动项目测试,访问http://localhost:9010/e-book-product/product/list三次过后就会出现这个:
在这里插入图片描述
提示请求访问次数过多。说明限流成功。

网关的2层超时调优

代码和限流一样,只需要修改配置文件。
先做一个测试,在服务端product中的方法中加入睡眠2秒。
在这里插入图片描述
然后启动zuul和product进行测试:
在这里插入图片描述
就会访问超时。
在这里插入图片描述
通过这个图我们就可以明白,先是访问的hystrix,我们设置睡眠的时间为2秒,所以就会死掉。
在配置文件中重新设置超时时间:

#第一层hystrix超时时间设置
#默认情况下是线程池隔离,超时时间1000ms
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=8000
#第二层ribbon超时时间设置:设置比第一层小
# 请求连接的超时时间: 默认5s
ribbon.ConnectTimeout=5000
# 请求处理的超时时间: 默认5s
ribbon.ReadTimeout=5000

需要注意的是ribbon的时间不能超过hystrix。
重新启动测试:
在这里插入图片描述
访问成功。
好了,服务网关的讲解就结束了,如果想要demo的资料可以叫我QQ997355706

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值