服务对外提供接口以供不同站点之间使用:Spring Cloud Feign使用记录及携带token请求


  在开发 Spring Cloud 微服务的时候,我们知道,服务之间都是以 HTTP 接口的形式对外提供服务的,因此消费者在进行调用的时候,底层就是通过 HTTP Client 的这种方式进行访问。当然我们可以使用JDK原生的 URLConnection、Apache 的 HTTP Client、Netty 异步 Http Client,Spring 的 RestTemplate 去实现服务间的调用。但是最方便、最优雅的方式是通过 Spring Cloud Open Feign 进行服务间的调用。Spring Cloud 对 Feign 进行了增强,使 Feign 支持 Spring Mvc 的注解,并整合了 Ribbon 等,从而让 Feign 的使用更加方便。

  Feign是一个声明式的Web服务客户端,使用Feign可使得Web服务客户端的写入更加方便。 它具有可插拔注释支持,包括Feign注解和JAX-RS注解、Feign还支持可插拔编码器和解码器、Spring Cloud增加了对Spring MVC注释的支持,并HttpMessageConverters在Spring Web中使用了默认使用的相同方式。Spring Cloud集成了Ribbon和Eureka,在使用Feign时提供负载平衡的http客户端。

  Feign作用:可以解决不同服务器接口之间的相互调用,即跨域请求!feign结合eureka注册中心,把不同的服务项目注册到eureka中,通过feign客户端进行调用,可以解决负载均衡问题。

  接下来就简单讲述一下Feign的入门使用

一、引入依赖及配置编写

1、引入依赖

<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-gson</artifactId>
    <version>10.2.3</version>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
    <version>2.1.1.RELEASE</version>
</dependency>

2、编写配置文件

@Configuration public class FeignConfiguration { @Bean public Contract feignContract() { return new Contract.Default(); } @Bean Logger.Level feignLoggerLevel() { return Logger.Level.FULL; } @Bean Decoder feignDecoder() { return new GsonDecoder(); } @Bean Encoder feignEncoder() { return new GsonEncoder(); } }

3、在应用主类Application里,通过@EnableFeignClients注解开启Spring Cloud Feign的支持功能。

// 在启动类上加上注解 // 开启 Feign 扫描支持
@EnableFeignClients

二、编写Feign接口及使用

1、编写Feign接口

  @FeignClient注解指定服务名来绑定服务,然后再使用Spring MVC的注解来绑定具体该服务提供的REST接口。

@FeignClient(name = "myApi", url = "http://localhost:8080") public interface MyService { // 调用另外一个服务的接口
    @RequestLine("GET /getUsers?searchString={searchString}") @Headers("Content-Type: application/json") List<User> getUsers(@Param("searchString") String searchString); }

2、使用接口

  Feign接口不需要实现类,可直接调用

    private MyService myService; @GetMapping("/userList") public List<User> getUsers(@RequestParam String searchString){ List<User> userList = myService.getUsers(searchString); return userList; }

三、携带token请求

  为了安全考虑要访问的服务的接口需要token验证才能访问,因此需要携带token才能访问。关于新的服务搭建安全框架,使用与要访问的平台一致的token生成和验证机制,这里就不赘述了。

1、方案一:直接在@Headers注解中加token

  这种方案可以用来测试,因为,这种方式token是写死的,不能根据浏览器携带的token进行验证。

@FeignClient(name = "myApi", url = "http://localhost:8080") public interface MyService { @RequestLine("GET /getUsers?searchString={searchString}") // 直接在@Headers注解中加token
    @Headers({"Content-Type: application/json", "Authorization: Bearer eyJh..."}) List<User> getUsers(@Param("searchString") String searchString); }

2、方案二:根据浏览器动态获取token

如何从浏览器中拿到token?

  可以看到javax.servlet.http包下有个getHeader的方法,可以获得当前浏览器Header中的信息。

如何将token放到跨域请求中?

  在fegin包中的请求拦截器RequestInterceptor有个apply方法,该方法的默认实现如下:

  可以看到,默认的Authorization是通过用户名和密码进行base64加密得到的,跟我们的token生成方式不一样,所以直接使用默认的是无法验证通过的,因此,只需实现RequestInterceptor,重写apply方法即可

解决方案

  编写配置类,实现RequestInterceptor,重写apply方法,把浏览器header拿到的token放进去。

@Slf4j @Configuration @AllArgsConstructor public class NimBusRequestInterceptor implements RequestInterceptor { private HttpServletRequest req; private static final String HEADER_STRING = "Authorization"; @Override public void apply(RequestTemplate requestTemplate) { // 如果header没有auth头,从cookie获取token
        String token = req.getHeader(HEADER_STRING); Cookie[] cookies = req.getCookies(); if (cookies != null && cookies.length > 0) { for (Cookie cookie : cookies) { if (Objects.equals(cookie.getName(), "token")) { try { token = URLDecoder.decode(cookie.getValue(), StandardCharsets.UTF_8.name()); } catch (UnsupportedEncodingException e) { log.error(LogUtil.getStack(e)); } } } } requestTemplate.header(HEADER_STRING, token); } }

  以上就实现了Feign基本使用与携带token请求。

原文链接:https://www.modb.pro/db/32126


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM