SpringCloud分布式(四)分布式网关Zuul使用详解

现有微服务的两点不足:

  1. 对于在微服务体系中、和EurekaServer通讯的微服务来讲,使用服务名即可访问。但是对于手机、web端等外部访问者仍然需要和N多服务器交互,需要记忆他们的服务器地址、端口号等。一旦内部发生修改,很麻烦,而且有时候内部服务器是不希望外界直接访问的。

  2. 各个业务系统的人无法自由的维护自己负责的服务器;

  3. 现有的微服务都是“我家大门常打开”,没有做权限校验。如果把权限校验代码写到每个微服务上,那么开发工作量太大。

zuul就是一个提供了请求路由、验证登录等功能的API网关微服务。
一、搭建Zuul服务
a)新建一个Spring项目,勾选Zuul、EurekaDiscovery。
b)***Application使用@EnableZuulProxy开启Zuul功能。
c)application.properties中加入
server.port=8888
spring.application.name=apigate
eureka.client.serviceUrl.defaultZone=http://127.0.0.1:8080/eureka/

二、请求路由
在配置中加入zuul.routes.<服务名>=请求路径这样的格式。比如zuul.routes.restservice1=/restservice1/** 当用户请求http://127.0.0.1:8888/restservice1/person/getById?id=1的时候就会访问restservice1服务的person/getById?id=1。
如果给web项目设置spring.application.name=testweb2,那么如果如下配置
zuul.routes.testweb2=/web/**
那么当访问http://127.0.0.1:8888/web/test/test1的时候就会访问testweb2项目的/test/test1

我们一般管restservice1叫zuul的“上游(upstream)服务器”。
注意:如果在“上游服务器”接口服务上设置了断点,并且断的时间稍微长一点,就会导致zuul这边收到超时错误。
这样对于外部访问者只要和http://127.0.0.1:8888打交道就行了,不需要直接和具体某个服务通讯。
网站内部如何通过Eureka实现自动扩容,对外再借助于Zuul实现前端服务器的自动扩容。这是微服务架构牛逼的地方。
不建议用zuul做纯web站的网关,zuul只做接口服务的网关。web站的网关建议用nginx。

三、请求过滤
支持ZuulFilter,可以在请求被路由之前进行权限校验等。
import javax.servlet.http.HttpServletRequest;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;

public class CheckFilter extends ZuulFilter {

@Override
public Object run() throws ZuulException {
	RequestContext ctx = RequestContext.getCurrentContext();
	HttpServletRequest request =  ctx.getRequest();
	String token = request.getParameter("token");
	if(token==null||!token.equals("123"))//请求中有token=123就认为认证通过
	{
		System.out.println("token错误");
		ctx.setSendZuulResponse(false);//不向上游服务器转发请求了
		ctx.setResponseStatusCode(401);//给下游调用者返回的错误码
	}
	return null;
}

@Override
public boolean shouldFilter() {
	return true;
}

@Override
public int filterOrder() {
	return 0;
}

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

}

在***Application中加入
@Bean
CheckFilter filter1()
{
return new CheckFilter();
}
注意Zuul服务器和“上游服务器”是运行在两个进程甚至两台服务器上,因此在Zuul中requeset.setAttribute中设置的值在“上游服务器”中获取不到。在ZuulFilter中可以通过下面的方式向“上游服务器”传递报文头:
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
ctx.addZuulRequestHeader(“X-MyHeader1”, “hello”);
在“上游服务器”中的请求头中就会有"X-MyHeader1"值。

ZuulFilter其他filterType:pre(请求被路由之前调用);routing(路由请求时被调用);error:发生错误时候调用;post:在routing和error过滤器后调用;

可以编写postFilter在给上游服务器发过来的响应发给下游请求者之前进行添加报文头等的处理:
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;

public class PostFilter extends ZuulFilter {

@Override
public Object run() throws ZuulException {
	RequestContext ctx = RequestContext.getCurrentContext();
	ctx.addZuulResponseHeader("X-Shit", "6666");
	return null;
}

@Override
public boolean shouldFilter() {
	return true;
}

@Override
public int filterOrder() {
	return 0;
}

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

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章