RestTemplate方式进行远程调用存在的问题
Feign是一个声明式的Http客户端
使用步骤:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
@GetMapping注解在Spring MVC中和Feign中都可以使用,用于定义Restful的接口,但它们的用途不同。在Spring MVC中,它用于将HTTP GET请求映射到指定的处理方法上;而在Feign中,它用于定义Feign客户端接口中的方法,用于向远程服务发送HTTP GET请求。
@FeignClient("userservice") // 指定要请求的服务名称
public interface UserClient {
@GetMapping("/user/{id}") // GetMapping是标明请求方式,不仅仅是Controller中的监听Get请求,这里是发送请求的方式
User findById(@PathVariable Long id);
}
@Resource
private UserClient userClient;
User user = userClient.findById(order.getUserId());
# Feign日志级别
feign:
client:
config:
default:
loggerLevel: HEADERS
方式二:在Configuration类中声明一个对应类型的Bean
Feign的底层客户端实现有三种:
这样我们就可以切换客户端并配置连接池来改善性能
Feign的性能优化可以从下面2个方面入手:
替换客户端实现为HttpClient:
<!-- feign的httpclient-->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
feign:
client:
config:
default:
loggerLevel: BASIC
httpclient:
enabled: false
max-connections: 200
max-connections-per-route: 50 # 每个路径的最大连接
缺点是会造成紧耦合,并且还需要在实现类中重新写一遍@PathVariable这种注解
抽取Feign为单独模块时,要注意到其他微服务的@ComponentScan是只能扫描到同级别及以下的类,为了让其他微服务扫描到Feign模块中的FeignClient,需要在@EnableFeignClients注解上增加参数(推荐第二种)
<!-- nacos客户端依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- 网关依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
server:
port: 10010
spring:
application:
name: gateway
cloud:
nacos:
server-addr: localhost:8848 # nacos服务器地址
gateway:
routes:
- id: user-service # 路由id,自定义,只要唯一即可
uri: lb://userservice # 路由的目标地址 lb=LoadBalance负载均衡, 后面跟服务名称,会被nacos注册中心对照为服务地址
predicates: # 路由断言,也就是判断哪些请求模式是属于这个路由的
- Path=/user/**
这就搭建完成了,以后请求都发到网关,网关判断后通过注册中心找到对应服务,把请求转过去
配置文件中写的断言规则path只是字符串,会被Predicate Factory读取并处理,转变为路由判断条件,之后由对应的断言工厂进行判断,还有其他断言可以使用:
网关中的过滤器,可以对进入网关的请求和微服务返回的响应进行处理
过滤器的添加也是在配置文件.yml中,给某服务加过滤器,就修改之前的配置为:
server:
port: 10010
spring:
application:
name: gateway
cloud:
nacos:
server-addr: localhost:8848
gateway:
routes:
- id: user-service
uri: lb://userservice
filter:
- AddRequestHeader=Greeting, Hello World! # 添加请求头过滤器工厂
predicates:
- Path=/user/**
如果想给所有的服务都加过滤器,可以用默认过滤器,对所有路由都生效
spring:
application:
name: gateway
cloud:
nacos:
server-addr: localhost:8848 # nacos服务器地址
gateway:
routes:
......
default-filters:
- AddRequestHeader=Greeting, Hello world! # 添加请求头
全局过滤器也是作用于所有请求和微服务响应,与默认过滤器的区别是,它需要自己使用代码实现其逻辑:
//@Order(1) 设置过滤器的优先级,越小越高, -1最大,也可以通过实现Ordered接口完成优先级配置
@Component
public class AuthorizeFilter implements GlobalFilter, Ordered{
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain){
// 1.获取请求参数
ServerHttpRequest request = exchange.getRequest();
MultiValueMap<String, String> params = request.getQueryParams();
// 2.获取参数中的authorization参数
String authorization = params.getFirst("authorization");
// 3.判断参数值是否等于admin
if("admin".equals(authorization)){
// 4.相等就放行
return chain.filter(exchange);
}else{
// 5.不等就拦截
// 设置状态码
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
// 拦截
return exchange.getResponse().setComplete();
}
}
@Override
public int getOrder(){ return -1;}
}
三种过滤器是放在一个集合里排序的,排序规则是:
跨域问题:浏览器禁止请求发起者与服务端发生跨域ajax请求,请求被浏览器拦截
浏览器采用同源策略,需要网页和其调用的接口的 协议、域名、端口 都一致,不一致它会觉得有风险。
CORS 是一个 W3C 标准,全称是“跨源资源共享”(Cross-origin resource sharing),或者通俗地
称为“跨域资源共享”。它允许浏览器向跨源的服务器,发出XMLHttpRequest请求,从而克服AJAX
只能同源使用的限制。
网关处理跨域采用的就是CORS,只需要在配置中进行添加:
spring:
cloud:
gateway:
globalcors: # 全局的跨域处理
add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题
corsConfigurations:
'[/**]': # 对所有的请求生效
allowedOrigins: # 允许哪些网站的跨域请求
- "http://localhost:8090"
- "http://www.leyou.com"
allowedMethods: # 允许的跨域ajax的请求方式
- "GET"
- "POST"
- "DELETE"
- "PUT"
- "OPTIONS"
allowedHeaders: "*" # 允许在请求中携带的头信息
allowCredentials: true # 是否允许携带cookie
maxAge: 360000 # 这次跨域检测的有效期