• 服务对外提供接口以供不同站点之间使用: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请求。

  • 相关阅读:
    ASP.NET State Service
    C# winform 打印当前窗体
    js计算时间之差
    转 Javascript中event.keyCode键码值表收藏
    从客户端中检测到有潜在危险的 Request.Form
    从VS2005项目转换为VS2008项目 转载
    C# Windows DataGridView 判断CheckBox 选取的方法
    在Visual Studio 2005中调试SQL Server 2005的存储过程
    ASP.NET Ajax 中出现的 sys 未定义(sys undefined)解决方法总结
    KubeMeet 直播 | 现场直击大规模集群、混合环境下的云原生应用交付难题
  • 原文地址:https://www.cnblogs.com/goloving/p/13667100.html
Copyright © 2020-2023  润新知