一、OpenFeign 是什么?
前面实现服务间调用的 http 客户端是 RestTemplate
弊端:传参需要手动拼接参数
参数==xx & 参数=xx
{参数:xx,参数:xx}
OpenFeign 是 SpringCloud 提供的声明式 HTTP 客户端,能够使用 SpringMVC 的注解,实现远程服务的调用。
二、OPenFeign 使用方法?
1)加依赖
2)启动类加
@EnableFeignClients(basePackages = "com.blb.orderservice.client")
2)编写接口
@FeignClient("product-service")
public interface ProductServiceClient {
@GetMapping("product-page")
ResponseEntity
@PostMapping("product")
ResponseEntity
@PutMapping("product")
ResponseEntity
@DeleteMapping("product/{id}")
ResponseEntity
}
4)使用接口
@Autowared
Feign接口 xxx;
xxx.方法(...)
三、OpenFeign 的优化方式
1)OpenFeign 客户端优化
OpenFeign 默认使用 JDK 自带 HttpConnection 实现 http 调用,不带连接池,资源利用率低
可以选用 OKHttpClient、ApacheHttpClient 或 ApacheHC5 带连接池,效率更高
选用下配置之一
feign.okhttp.enabled=true
feign.httpclient.enabled=true
feign.httpclient.hc5=true
2) 请求响应压缩
将请求和响应数据进行压缩,占用带宽小,速度更快
feign.compression.request.enabled=true
feign.compression.response.enabled=true
feign.compression.request.mime-types=text/xml,application/xml,application/json
feign.compression.request.min-request-size=2048
3)日志跟踪
logging.level.com.blb.orderservice.client.ProductServiceClient: debug
@Configuration
public class FeignConfig {
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
}
NONF 没有,默认
BASIC 基本的方法名、URL、响应码
HEADER 请求和响应头
FULL 完整,包含完整的请求响应报文
4)启动熔断器
feign.hystrix.enabled=true
编写熔断降级类:
@Component
public class ProductServiceClientFackback implements ProductServiceClient{
@Override
public ResponseEntity
Product product = new Product();
product.setName("降级数据");
return ResponseEntity.ok(product);
}
}
设置降级类
@FeignClient(value = "product-service",fallback = ProductServiceClientFackback.class)
四、OpenFeign 的实现原理?
为什么只用写个接口就能实现远程服务的调用??
需要使用的技术:
1)接口的扫描(JDK 扫描包+反射读取接口信息)
2)接口的实现(JDK 的动态代理,创建接口的实现类返回对象) 动态代理
3)调用的过程
读取 FeignClient 中的服务名,到注册中心查询服务的 IP 和端口
请求编码:将 IP 和端口以及接口定义 URL 和参数拼接起来
使用配置的 HTTP 客户端发送请求,获得响应结果
响应解码:对响应结果进行解码,返回数据
五、Gateway 是什么?
SpringCloud 提供的 APl 网关组件,主要的作用是:统一的路由和鉴权,能够提高微服务系统的安全性
我们可以将微服务的 IP 和端口隐藏起来,唯一暴露出来的就是网关的端口,前端的请求都通过网关网关路由到每个微服务
六、Gateway 的入门
1)新建微服务项目
2)注册到 nacos 上
3)配置路由规则
七、Gateway 的路由规则?
重点: 导入 Gateway 依赖,一定不要引入 springMVC 的依赖,会造成冲突
配置路由规则实现请求的转发
spring:
cloud:
gateway:
routes:
- id: 路由名称
uri: 转发的地址
predicates:
- 谓词条件
案例1: cookie中包含某个值就进行路由
spring:
cloud:
gateway:
routes:
- id: after_route
uri: https://example.org
predicates:
- Cookie=mycookie,mycookievalue
案例2:按时间前后转发
spring:
cloud:
gateway:
routes:
- id: after_route
uri: https://example.org
predicates:
- After=2017-01-20T17:42:47.789-07:00[America/Denver]
spring:
cloud:
gateway:
routes:
- id: after_route
uri: https://example.org
predicates:
- Before=2017-01-20T17:42:47.789-07:00[America/Denver]
spring:
cloud:
gateway:
routes:
- id: between_route
uri: https://example.org
predicates:
- Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver]
案例3:按请求方法转发
spring:
cloud:
gateway:
routes:
- id: method_route
uri: https://example.org
predicates:
- Method=GET,POST
案例4:按路径转发某个服务
spring:
cloud:
gateway:
routes: # 路由规则
- id: product-service-route # 路由名称
uri: lb://product-service # 路由的服务
predicates: # 包含路径
- Path=/product/**,/products/**,/product-page/**
八、Gateway 的过滤器?
Gateway 网关可以通过过滤器对请求进行权限验证
Gateway 运行的过程:
1)客户端发送请求给 Gateway
2)Gateway 将请求交给处理器映射
3)处理器映射通过路由规则找到处理器
4)处理器将请求发送给被代理的服务,请求会经过一个过滤器链
5)过滤器有前置后置两种,前置可以执行逻辑判断,对请求进行拦截
6)后置过滤器可以在响应数据上添加内容或进行日志收集等
过滤器按影响范围分为两种:
1)局部过滤器(影响部分路由)
2)全局过滤器(影响所有路由)
案例:全局过滤器验证 Tocken,验证失败不允许访问服务
/**
* 全局 Token驗證的過濾器
*/
@Component
public class TokenFiler implements GlobalFilter, Ordered {
/**
* 過濾
*
* @param exchange
* @param chain
* @return
*/
@Override
public Mono
// 獲得請求和響應
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
// 獲得 token參數
String token = request.getQueryParams().getFirst("token");
// 驗證token,成功就放行
if ("123456".equals(token)) {
// 放行
return chain.filter(exchange);
}
// 设置401响应代码
response.setStatusCode(HttpStatus.UNAUTHORIZED);
response.getHeaders().add("Content-Type", "text/html;charset=UTF-8");
// 保证响应信息
DataBuffer wrap = response.bufferFactory().wrap("验证错误,需要登录".getBytes(StandardCharsets.UTF_8));
// 返回参数给客户端
return response.writeWith(Mono.just(wrap));
}
@Override
public int getOrder() {
// 值越大,過濾器執行越靠後
return 0;
}
}
好文链接
发表评论