zoukankan      html  css  js  c++  java
  • SpringCloud Alibaba微服务番外篇二

    概述a

    还记得我们之前创建订单的流程吗?

    通过网关调用order-service的create方法,然后order-service再通过feign调用account-service 的reduce 和 product-service的 deduct 方法进行业务逻辑处理。
    在这里插入图片描述

    当我们项目整合好oauth2后再来调用之前的方法发现调用异常,查看后端日志发现如下的错误信息:

    org.springframework.security.authentication.InsufficientAuthenticationException: Full authentication is required to access this resource
    
    Request processing failed; nested exception is feign.FeignException$Unauthorized: status 401 reading AccountFeign#reduce(String,BigDecimal)
    

    错误信息告诉我们是接口未授权导致访问异常,实际上我们已经将access_token放在了header上,如下:
    在这里插入图片描述

    最后通过对自定义异常类进行跟踪发现是access_token经过order-service访问account-service时丢失了,获取的accessToken为null。
    在这里插入图片描述

    本节主要是来解决使用feign调用时access_token丢失的问题。

    代码示例

    Feign 支持请求拦截器,在发送请求前,可以对发送的模板进行操作,例如设置请求头等属性,自定请求拦截器只需要实现 RequestInterceptor 接口,该接口的方法有 RequestTemplate 类型的参数,我们可以根据实际情况对请求的信息进行调整。

    public interface RequestInterceptor {
        void apply(RequestTemplate var1);
    }
    

    我们要实现的功能很简单,就是取出原来的请求头,再将其传递给下游服务,在order-service中建立 FeignRequestInterceptor 并给其添加@Configuration 注解,代码如下:

    /**
     * Description:
     * 微服务之间feign调用请求头丢失的问题
     * @author javadaily
     * @date 2020/02/24 9:28
     */
    @Configuration
    @Slf4j
    public class FeignRequestInterceptor implements RequestInterceptor {
        @Override
        public void apply(RequestTemplate template) {
            HttpServletRequest httpServletRequest =   getHttpServletRequest();
            if(httpServletRequest!=null){
                Map<String, String> headers = getHeaders(httpServletRequest);
                // 传递所有请求头,防止部分丢失
                //此处也可以只传递认证的header
                //requestTemplate.header("Authorization", request.getHeader("Authorization"));
                for (Map.Entry<String, String> entry : headers.entrySet()) {
                    template.header(entry.getKey(), entry.getValue());
                }
                log.debug("FeignRequestInterceptor:{}", template.toString());
            }
        }
    
    
        private HttpServletRequest getHttpServletRequest() {
            try {
                return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            } catch (Exception e) {
                return null;
            }
        }
    
        /**
         * 获取原请求头
         */
        private Map<String, String> getHeaders(HttpServletRequest request) {
            Map<String, String> map = new LinkedHashMap<>();
            Enumeration<String> enumeration = request.getHeaderNames();
            if(enumeration!=null){
                while (enumeration.hasMoreElements()) {
                    String key = enumeration.nextElement();
                    String value = request.getHeader(key);
                    map.put(key, value);
                }
            }
            return map;
        }
    }
    

    完成配置后重启服务器,再次调用create方法,正常返回响应结果。
    在这里插入图片描述

    系列文章

    SpringCloud实战

    在这里插入图片描述

  • 相关阅读:
    增强iOS应用程序性能的提示和技巧(25个)
    [iOS]用instancetype代替id作返回类型有什么好处?
    把cygwin加入右键菜单
    NSRange
    Centos7下安装MySQL
    (转)php 操作redis全部方法。
    unbuntu 安装php5.6
    unbuntu 安装nginx
    unbuntu 安装MySQL
    Ubuntu16.04下实现MySQL主从复制
  • 原文地址:https://www.cnblogs.com/hzcya1995/p/13295893.html
Copyright © 2011-2022 走看看