avatar

目录
服务网关&Zuul综合使用

第7章 服务网关

服务网关和Zuul

为什么需要网关服务?

  • 统一的request入口

![屏幕快照 2018-12-27 上午11.21.51](20181227111536420/屏幕快照 2018-12-27 上午11.21.51.png)

服务网关的要素:

  • 稳定性、高可用
  • 性能、并发性
  • 安全性
  • 扩展性
  • (很多非业务功能在这里完成)

常用的网关方案:

  • Nginx + Lua
  • Kong:(商业软件)
  • Tyk:开源,Go语言开发
  • Spring Cloud Zuul:以java技术栈为主构建微服务 适合使用zuul 快速上手 但性能比Nginx差

Zuul的特点

  • 路由+过滤器 = Zuul
  • 核心:一系列过滤器

Zuul的四种过滤器API

  • 前置(Pre)
  • 路由(Route)
  • 后置(Post)
  • 错误(Error)

fillter之间通过RequestContext进行交互

![屏幕快照 2018-12-27 上午11.46.07](20181227111536420/屏幕快照 2018-12-27 上午11.46.07.png)

zuul http请求生命周期

![屏幕快照 2018-12-27 上午11.47.12](20181227111536420/屏幕快照 2018-12-27 上午11.47.12.png)

pre:参数校验..

routing:转发,重写http请求…

post:对结果进行加工

error:发生异常时会到达,做统一异常处理

customer:自定义过滤器

Zuul:路由转发&自定义&排除

0、新建项目:api-gateway

pom

Code
1
2
3
config-client 
eureka-discovery
zuul

1、路由转发

启动类:@EnableZuulProxy

通过访问gateway,路由到product/list

Code
1
http://localhost:9000/product/product/list	项目名/路径

2、自定义路由

yaml
1
2
3
zuul:
routes:
config: /myconfig/**

访问:

Code
1
2
3
都可以
http://localhost:9000/myconfig/order-dev.yml
http://localhost:9000/config/order-dev.yml

3、禁止路由

yaml
1
2
3
zuul:
ignored-patterns:
- /**/product/list

Zuul:Cookie&动态路由

1、Cookie

使用zuul后,默认Cookie是不传递的,配置使Cookie不被过滤掉

yaml
1
2
3
4
5
6
7
zuul:
routes:
config:
path: /myconfig/**
serviceId: config
# 将set集合置null,就不会过滤掉Cookie
sensitiveHeaders:

2、动态路由

改路由配置后动态生效,不用重启gateway

Code
1
2
3
思路
1、只需要使用统一配置中心,把zuul节点的配置放在git端就可以动态更新yml了
2、yml动态更新了,配置类也需要动态注入,使用@RefreshScope(一旦yml变化了,新配置就重新注入类)

在启动类添加:

java
1
2
3
4
5
@ConfigurationProperties("zuul")
@RefreshScope
public ZuulProperties zuulProperties(){
return new ZuulProperties();
}

Zuul:路由和高可用小结

典型应用场景

pre:限流、鉴权、参数校验、请求转发…

post:统计、日志

Zuul高可用

  • 多个节点注册到Eureka Server 实现高可用
  • 内部:a调用b 可以变成 a > zuul服务 > b
  • 外部:Nginx+Zuul “混搭”,取长补短

下章节探讨zuul过滤器相关

第8章 Zuul综合使用

Zuul:Pre和Post过滤器

客户端 > Nginx(负载均衡) > Zuul > …

1、Pre过滤器

应用场景:统一在Zuul做权限校验

场景细节:希望所有经过zuul的请求 带 token参数 且 不为null(实际业务中需要结合数据库进行更多校验);如果不带参,则校验不通过,返回401(权限不足)。

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// FilterConstants
package com.mxx.apigateway.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_DECORATION_FILTER_ORDER;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;

@Component
public class TokenFilter extends ZuulFilter{

// FilterConstants

@Override
public String filterType() {
return PRE_TYPE;
}

// 越小越前执行
@Override
public int filterOrder() {
return PRE_DECORATION_FILTER_ORDER - 1;
}

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

// 过滤逻辑写在这
@Override
public Object run() throws ZuulException {
RequestContext requestContext = RequestContext.getCurrentContext();
HttpServletRequest request = requestContext.getRequest();
String token = request.getParameter("token");

if(StringUtils.isEmpty(token)){
requestContext.setSendZuulResponse(false);//zuul 不通过
requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());//401 没权限
}
return null;
}
}

测试

Code
1
2
3
http://localhost:9000/myconfig/order-dev.yml?token=123	# 可以
http://localhost:9000/myconfig/order-dev.yml?token= # 不行
http://localhost:9000/myconfig/order-dev.yml # 不行

2、Post过滤器

应用场景:统一请求结束后做处理

场景细节:加个header参数

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package com.mxx.apigateway.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletResponse;
import java.util.UUID;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.POST_TYPE;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.SEND_RESPONSE_FILTER_ORDER;

@Component
public class AddResponseHeaderFilter extends ZuulFilter{
@Override
public String filterType() {
return POST_TYPE;
}

@Override
public int filterOrder() {
return SEND_RESPONSE_FILTER_ORDER -1;
}

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

@Override
public Object run() throws ZuulException {
RequestContext requestContext = RequestContext.getCurrentContext();
HttpServletResponse response = requestContext.getResponse();
response.setHeader("X-Foo", UUID.randomUUID().toString());

return null;
}
}

测试:浏览器控制台 > …

Zuul:限流

1、限流

  • 限制客户端请求速率

  • 时机:请求转发前调用(放在前置过滤器最靠前的地方:pre里有限流、鉴权,则限流改早于鉴权)

  • 方案:比如令牌桶限流(参考我的【高并发专题】)

Zuul:鉴权&添加用户服务

业务需求:

  • order/create 只能买家访问
  • order/finish 只能卖家访问
  • product/list 都可以访问

所以过滤器要区分买家/卖家…如何区分?… header cokkie …先完成登录才会看到信息 … 先把用户服务建起来

1、添加用户服务

Code
1
2
3
4
数据库
新建项目:user
业务:模拟买家卖家登录功能实现
业务:完结订单接口开发

2、权限校验

Code
1
2
3
4
业务:完成权限校验
优化场景:硬编码到filer不适合 权限特别多/经常变动的场合
优化方案:分开写买家卖家的权限类,在是否需要拦截的方法里判断用户类型,决定是否放行,以后有新角色只需要加类就行
注意:api-gateway不要连数据库或者直接api调用服务,建议都利用redis做中间

方案:

  • pre
  • 分布式session Vs OAuth2

Zuul:跨域

  • ajax跨域问题

  • 解决方案:在类或方法上加@CrossOrigin (不推荐)

  • 解决方案:在Zuul里增加CorsFilter过滤器(就是将CorsFilter配置好后注入就行)

具体代码:

Code
1
2
config/CorsConfig

文章作者: Machine
文章链接: https://machine4869.gitee.io/2018/12/27/20181227111536420/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 哑舍
打赏
  • 微信
    微信
  • 支付宝
    支付宝

评论