SpringCloud之——ZUUL网关

网关简单的说就是微服务提供的统一的对外访问的接口,换言之就是所有的服务在请求到达服务之前,都要先经过网关,那么,这样的设计就便于我们做统一的权限验证等工作!
与eureka一样,zuul也是作为一个独立的服务存在
同时附上我练习时搭建的一个简单的SpringCloud项目,其中包含了feign、swagger-ui、rabbitmq、redis、aop、定时任务、文件上传于下载、excel导出、多数据源配置等demo,该项目也包含了SpringCloud的常用组件:
下载链接://download.csdn.net/download/weixin_45417573/12104123
一、创建服务
创建一个Springboot服务
二、添加依赖

<!-- 网关 -->
  	<dependency>
  		<groupId>org.springframework.cloud</groupId>
  		<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
  	</dependency>

当然除了添加zuul的依赖还需要添加eurekaclient的依赖和web依赖
三、添加主启动类的注解

@EnableZuulProxy

四、修改yml配置

zuul:
  host:
  #超时时间
    connect-timeout-millis: 20000
    socket-timeout-millis: 60000
    #哪些服务
  routes:
    jt-order:
      path: /order/**
      serviceId: jt-order
      #去除前缀
      stripPrefix: false
    jt-user:
      path: /user/**
      serviceId: jt-user
      stripPrefix: false
    jt-web:
      path: /web/**
      serviceId: jt-web
      stripPrefix: false

到这里zuul服务就已经完成了,后面,就说说zuulFilter过滤器的使用了
五、过滤器
注意,自定义过滤器需继承ZuulFilter,并重写其方法

package com.wwy.filter;

import org.springframework.stereotype.Component;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.exception.ZuulException;

/**
 * 
 * @author wwy
 * @date 2019年11月29日
 * @version v0.0.1
 *用户验证过滤器
 */
@Component
public class Filter extends ZuulFilter{
	/**
	 * 过滤器过滤哪些服务(过滤全部直接返回true)
	 */ 
	@Override
	public boolean shouldFilter() {
	//如果要过滤部分服务可以通过判断访问的服务名来返回不同的boolean值
	RequestContext ctx = RequestContext.getCurrentContext();
		String serviceId = (String) ctx.get(FilterConstants.SERVICE_ID_KEY);
		if(serviceId.equals("jt-order")) {
			return true;
		}
	
		return false;
	}
	/**
	 * 过滤器中执行的代码
	 */
	@Override
	public Object run() throws ZuulException {
		//TODO 验证权限的代码,在这里写一段代码模拟做一个权限的验证,仅供参考
		//注意,这里如果需要用到request或者response我们可以通过以下方式获取
		RequestContext ctx = RequestContext.getCurrentContext();
		HttpServletRequest request = ctx.getRequest();
		HttpServletResponse response = ctx.getResponse();
		//通过request获取token
		String token=request.getHeader("token");
		if(token==null){
		//如果没有token,则阻止请求转发到相应的服务
		ctx.setSendZuulResponse(false);
		ctx.setResponseStatusCode(200);
		ctx.setResponseBody(JsonResult.err().code(JsonResult.NOT_LOGIN).toString());
	}
		return null;//这个返回值目前没有实际意义(留着将来扩折用的)
	}
	/**
	 * 过滤器顺序
	 */
	@Override
	public int filterOrder() {
		//这里的过滤器顺序必须要大于5
		return 6;
	}
	@Override
	public String filterType() {
		//指定过滤器的类型,比如前置、后置等
		return FilterConstants.PRE_TYPE;
	}

}

截止到这里一个基本的API网关就搭建完成了,但是还有很多可以优化的地方,例如我们上面说到,zuul整合了ribbon和hystirx,那么当我们服务转发不成功的时候,我们是否要进行重试?是否需要降级代码?
六、重试与降级
(1)添加依赖:

	<!-- ribbon重试 -->
  	<dependency>
	<groupId>org.springframework.retry</groupId>
	<artifactId>spring-retry</artifactId>
</dependency>

(2)增加配置:

#开启重试
zuul:
  retryable: true
  #超时时间和重试次数的配置
ribbon:
  ConnectTimeout: 1000
  ReadTimeout: 1000
  MaxAutoRetriesNextServer: 1
  MaxAutoRetries: 1

(3)新建降级类,实现FallbackProvider接口并重写方法

package com.wwy.fb;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
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;
import lombok.extern.slf4j.Slf4j;
/**
 * 服务的降级类
 * 当zuul转发请求失败时执行该类中的方法
 * @author wwy
 * @date 2020年1月6日
 * @version v0.0.1
 *
 */
@Slf4j
@Component
public class CarFB implements FallbackProvider{
	/**
	 * 指定服务转发失败时执行该代码
	 */
	@Override
	public String getRoute() {
		log.error("转发失败了哟");
		return null;
		//*和null为通配,如果要使用一个降级类通配所有的服务降级,则返回*或者null
	}
	/**
	 * 返回相应结果
	 */
	@Override
	public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
		
		return response();
	}
	/**
	 * 
	 * @return
	 */
	private ClientHttpResponse response() {
		return new ClientHttpResponse() {

			@Override
			public InputStream getBody() throws IOException {
				//返回错误信息
				return new ByteArrayInputStream("服务器后台错误".getBytes("UTF-8"));
			}

			@Override
			public HttpHeaders getHeaders() {
				//返回请求头格式为application/json(json格式)
				HttpHeaders h=new HttpHeaders();
				h.setContentType(MediaType.APPLICATION_JSON);
				return h;
			}

			@Override
			public HttpStatus getStatusCode() throws IOException {
				//返回状态信息
				return HttpStatus.INTERNAL_SERVER_ERROR;
			}

			@Override
			public int getRawStatusCode() throws IOException {
				//返回状态码
				return HttpStatus.INTERNAL_SERVER_ERROR.value();
			}

			@Override
			public String getStatusText() throws IOException {
	
				return HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase();
			}

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

}

现在网关的搭建就基本完成了,这里要注意两个问题:
1、测试时访问相应的服务必须要使用网关ip:网关端口+服务地址
2、zuul会在eureka注册中心拉取服务信息,也就是说即使zuul.routes:中我们什么都不配,服务依旧能转发成功。如果需要关闭方便测试,可使用如下配置

#ribbon:
#  eureka:
#    enabled: false

3、出于安全考虑,zuul默认会过滤掉一些敏感的请求头,例如:Cookie,set-Cookie,Authorization,如果开发中需要这些协议头,可以通过以下配置关闭对相应协议头的过滤:

zuul:
  sensitive-headers: xxx
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值