目录
一、Feign 简介
1、RestTemplate 远程调用中存在的问题
2、定义和使用 Feign 客户端
3、Feign 自定义配置
4、Feign 性能优化
5、Feign 最佳实践
6、Feign 使用问题汇总
二、Gateway 网关简介
1、搭建网关服务
2、路由断言工厂
3、路由的过滤器配置
4、全局过滤器
5、过滤器链执行顺序
6、网关的 cors 跨域配置
7、Gateway 网关使用问题汇总
Feign 是 Netflix 开发的声明式、模板化的 Http 客户端,Feign 可以帮助我们更快捷、优雅地调用Http API。
该远程调用的代码有以下问题:
在 SpringCloud 中,使用 Feign 非常简单,创建一个 Interface,并在接口上添加一些注解,代码就完成了。
(1)引入依赖
(2)添加 @EnableFeignClients 注解
(3)编写 Feign 客户端
上述注解声明了如下信息:
(4)OrderService 远程调用过程
该远程调用过程,就好像平常处理请求的逆过程:
Spring 虽然帮我们做好了配置,但是也允许我们修改默认配置。
配置 Feign 日志有 2 种方式:
(1)application/bootstrap 配置文件方式
(2)Java 代码方式
Feign 底层客户端实现:
- URLConnection:默认使用,java 原生 jdk,性能较差,不支持连接池;
- Apache HttpClient:支持连接池;(推荐)
- OKHttp:支持连接池;(推荐)
对 Feign 的性能优化,最重要的一点就是对底层实现的改变。
因此优化 Feign 的性能主要包括:
下面以 HttpClient 为例子,说明性能优化的步骤:
(1)引入依赖
(2)修改 application 配置文件
最佳实践是指,企业开发过程中,总结设计缺点,得出的一种相对比较好的使用方式。
通常会用到 2 种方式,各有利弊,按自己的需求使用:
- 继承:给消费者的 FeignClient 和提供者的 controller 定义统一的父接口,然后实现接口;
- 比如 order 模块要调用 user 模块的服务,就定义 UserClient 接口,继承 UserAPI;
- 缺点:耦合度高;
- 优点:遵从了契约;
- 抽取:将 FeignClient 抽取为独立模块,并且把接口有关的 POJO、默认的 Feign 配置都放到这个模块中,提供给所有消费者使用;
- 缺点:消费者可能会引入很多用不到的 api;
- 优点:耦合度低,层次分明;
我个人更喜欢第二种抽取的方式,下面使用这种方式做一个例子。
(1)创建 feign-api 模块
(2)引入 feign-api 模块
(3)消除报错
(1)Did you forget to include spring-cloud-starter-loadbalancer?
出错原因:
- SpringCloud Feign 在 Hoxton.M2 RELEASED 版本之后不再使用 Ribbon,而是使用 spring-cloud-loadbalancer,所以在不引入 spring-cloud-loadbalancer 的情况下会报错。
参考了很多解决方法,主要是要区别版本问题:
在包含 RELEASE 关键字的版本中,只有下面这样操作才能使用:
而在 2021 及更新版本中(也就是没有 RELEASE 关键字的版本),只需要如下操作:
为什么需要网关?
- 如果没有网关,那么所有人都可以访问我们所有的服务,但是有很多服务其实是不能对外公开的。
- 需要使用网关进行身份验证,通过后才能访问敏感服务。
- 一切请求需要先通过网关,才能到微服务。
因此,网关有如下功能:
SpringCloud 提供了 2 个组件实现网关功能:
Zuul 是基于 Servlet 的实现,属于阻塞式编程。
而 SpringCloudGateway 则是基于 Spring5 中提供的 WebFlux,属于响应式编程的实现,具备更好的性能。
(1)创建 gateway 模块
(2)编写路由配置以及 Nacos 地址
(3)测试网关功能
路由断言工厂 Route Predicate Factory,作用是:
下面以 After 举一个例子:
(1)添加断言规则 After
(2)访问 order 的服务
路由过滤器是:GatewayFilter。
- GatewayFilter 是网关中提供的一种过滤器,可以对进入网关的请求和微服务返回的响应做处理。
在这个过程中,过滤器就可对请求和响应做出各种各样的处理,这样往下游传递的数据中,就包含了修改后的信息。
具体有什么样的操作,就要看使用哪个过滤器工厂:
下面我们以添加一个请求头为例子:
(1)修改 application 配置文件
(2)编写 Controller,获取请求头信息
(3)编写默认过滤器 default-filter
如果我们想为所有的请求都添加 header 信息,也不需要给每一个路由都写上 filters。
全局过滤器是:GlobalFilter。
需求
定义全局过滤器,拦截请求,判断请求的参数是否满足下面条件:
- 参数中是否有 authorization;
- authorization 参数值是否为 admin;
- 如果同时满足则放行,否则拦截;
(1)定义实现类
(2)定义 filter 方法的运行逻辑
@Order(-1)
@Component
public class AuthorFilter implements GlobalFilter {
@Override
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 1.获取请求参数
ServerHttpRequest request = exchange.getRequest();
MultiValueMap params = request.getQueryParams();
// 2.获取请求参数中的 author 参数值
String author = params.getFirst("author");
// 3.判断是否等于 admin
if (author.equalsIgnoreCase("admin")) {
// 放行
return chain.filter(exchange);
}
// 4.不相等,获取响应
ServerHttpResponse response = exchange.getResponse();
// 4.1.设置状态码,401表示未登录
response.setStatusCode(HttpStatus.UNAUTHORIZED);
// 4.2.拦截请求
return response.setComplete();
}
}
(3)启动 gateway 的 application
请求进入网关会碰到三类过滤器:当前路由的过滤器、DefaultFilter、GlobalFilter。
请求路由后,会将当前路由过滤器和 DefaultFilter、GlobalFilter,合并到一个过滤器链(集合)中,排序后依次执行每个过滤器。
过滤器执行顺序:
- 每一个过滤器都必须指定一个 int 类型的 order 值:order 值越小,优先级越高,执行顺序越靠前;
- GlobalFilter 通过实现 Ordered 接口,或者添加 @Order 注解来指定 order 值,由我们自己指定;
- 路由过滤器和 defaultFilter 的 order 由 Spring 官方指定,默认是按照声明顺序从 1 递增;
- 当过滤器的 order 值一样时,会按照 defaultFilter > 路由过滤器 > GlobalFilter 的顺序执行;
由于一些页面可能需要从微服务中获取某些数据,此时需要发起 AJAX 请求,那么这就可能属于跨域请求的范畴。(一般我们的 web 页面端口都不会与微服务的相同,所以请求基本上都是跨域请求)
跨域请求不需要在微服务中处理,只需要在网关中处理即可。
跨域:域名不一致就是跨域,主要包括:
- 域名不同:www.taobao.com 和 www.taobao.org 和 www.jd.com 和 miaosha.jd.com;
- 域名相同,端口不同:localhost:8080 和 localhost:8081
跨域问题的 2 个要素:
需求:
- 使用 localhost:8090 发起请求,8090 发送的是 AJAX 的 GET 请求。
- 8090 发起的 AJAX 请求需要通过网关,在 AJAX 的目标地址中要用 10010 端口;
(1)编写 gateway 的配置文件
(2)端口 8090 的 AJAX 请求
Title
发起普通GET请求
(1)搭建网关服务时,报错 503
这是因为在 Spring Cloud 2020 版本以后,默认移除了对 Netflix 的依赖,其中就包括 Ribbon,官方默认推荐使用 Spring Cloud Loadbalancer 正式替换 Ribbon,并成为了 Spring Cloud 负载均衡器的唯一实现。
Loadbalancer 依赖: