• feign 请求携带请求头解决方案


    cloud 进行服务间调用时通常需要添加token作为请求头,下面是我自己的解决方案

    @Autowired
        OauthClient oauthClient;
        /**
         * 通过服务名调用
         */
        private static final String OAUTH_URL = "http://sclp-oauth";
    
        @PostMapping("/login")
        public Result login(@RequestBody Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {
            //设置请求头参数
            HttpHeaders headers = new HttpHeaders();
            //spring-cloud-oauth2-server /oauth/token 必须添加一下请求头
            headers.add("Authorization", "Basic c2NscC1jbGllbnQ6c2VjcmV0");
            headers.add("Content-Type", "application/x-www-form-urlencoded");
    
            //授权类型
            MultiValueMap params = new LinkedMultiValueMap();
            params.add("grant_type", "password");
            //添加请求参数
            for (Map.Entry e : parameters.entrySet()) {
                params.add(e.getKey(), e.getValue());
            }
            //发送请求
            HttpEntity<String> ans = restTemplate.exchange(OAUTH_URL + "/oauth/token",
                    HttpMethod.POST,
                    new HttpEntity<>(params, headers),
                    String.class);
    
            JSONObject jsonObject = JSONObject.parseObject(ans.getBody().toString());
            String access_token = (String) jsonObject.get("access_token");
            if (Objects.nonNull(access_token) && !Objects.equals("", access_token)) {
                Map<String, String> result = new HashMap<>(1);
                result.put("token", "bearer " + access_token);
                return Result.OK("登录成功!", result);
            } else {
                return Result.ERROR("登录失败!");
            }
        }
    

    但是上面的方案需要对每个请求添加请求头以及参数,非常麻烦,且没有使用到feign这种成熟的微服务调用方案,网上查询了一番,了解到可以统一给feign客户端添加请求头

    /**
     * @author JTY
     * @date 21-5-9 21:28
     * @description feign请求添加token、以及其他信息
     */
    @Slf4j
    public class FeignClientRequestInterceptor implements RequestInterceptor {
        @Override
        public void apply(RequestTemplate template) {
            HttpServletRequest httpServletRequest = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            if (httpServletRequest != null) {
                //获取头信息
                Map<String, String> headers = getHeaders(httpServletRequest);
                // 传递所有请求头,防止部分丢失
                Set<Map.Entry<String, String>> headerSet = headers.entrySet();
    
                //RequestTemplate添加请求头
                for (Map.Entry<String, String> e :
                        headerSet) {
                    template.header(e.getKey(), e.getValue());
                }
                // 请求客户端信息、权限信息
                if (httpServletRequest.getHeader(HttpHeaders.AUTHORIZATION) == null) {
                    //添加客户端信息
                    byte[] auth64Encode = Base64.getEncoder().encode(ConstantString.CLIENT_ID_SECRET.getBytes(StandardCharsets.UTF_8));
                    template.header(HttpHeaders.AUTHORIZATION, new String(auth64Encode));
                }
                log.debug("FeignRequestInterceptor:{}", template.toString());
            }
        }
    
        /**
         * 获取头信息
         *
         * @param request
         * @return
         */
        private Map<String, String> getHeaders(HttpServletRequest request) {
            Map<String, String> headerMap = new LinkedHashMap<>();
            Enumeration<String> enumeration = request.getHeaderNames();
            if (Objects.nonNull(enumeration)) {
                while (enumeration.hasMoreElements()) {
                    String key = enumeration.nextElement();
                    String value = request.getHeader(key);
                    headerMap.put(key, value);
                }
            }
            return headerMap;
        }
    }
    
    #开启feign hystrix 服务降级
    feign:
      hystrix:
        enabled: false  #true开启histrix 熔断,false 关闭熔断
      client:
        config:
          default:
            connectTimeout: 30000
            readTimeout: 30000
            loggerLevel: full #日志级别
            requestInterceptors: com.sclp.config.FeignClientRequestInterceptor #自定义请求拦截器
    

    此时需要关闭histrix熔断才会有效,否则HttpServletRequest httpServletRequest = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();获取到的request为空(由于histrix隔离策略默认且推荐使用Thread线程隔离,线程间无法共享request内容,因此获取到空,相关内容https://github.com/Netflix/Hystrix/wiki/How-it-Works#Isolation)

    #开启feign hystrix 服务降级
    feign:
      hystrix:
        enabled: false  #true开启histrix 熔断,false 关闭熔断
    

    若要开启histrix熔断,则可将熔断策略更换为信号量SEMAPHORE,另外可以自定义隔离策略共享线程间数据,
    参考自https://zhuanlan.zhihu.com/p/32046755

    /**
     * @author JTY
     * @date 21-5-9 22:33
     * @description
     */
    @Component
    @Slf4j
    public class FeignHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy {
    
        private HystrixConcurrencyStrategy delegate;
        public FeignHystrixConcurrencyStrategy() {
            try {
                this.delegate = HystrixPlugins.getInstance().getConcurrencyStrategy();
                if (this.delegate instanceof FeignHystrixConcurrencyStrategy) {
                    // Welcome to singleton hell...
                    return;
                }
                HystrixCommandExecutionHook commandExecutionHook = HystrixPlugins
                        .getInstance().getCommandExecutionHook();
                HystrixEventNotifier eventNotifier = HystrixPlugins.getInstance()
                        .getEventNotifier();
                HystrixMetricsPublisher metricsPublisher = HystrixPlugins.getInstance()
                        .getMetricsPublisher();
                HystrixPropertiesStrategy propertiesStrategy = HystrixPlugins.getInstance()
                        .getPropertiesStrategy();
                this.logCurrentStateOfHystrixPlugins(eventNotifier, metricsPublisher,
                        propertiesStrategy);
                HystrixPlugins.reset();
                HystrixPlugins.getInstance().registerConcurrencyStrategy(this);
                HystrixPlugins.getInstance()
                        .registerCommandExecutionHook(commandExecutionHook);
                HystrixPlugins.getInstance().registerEventNotifier(eventNotifier);
                HystrixPlugins.getInstance().registerMetricsPublisher(metricsPublisher);
                HystrixPlugins.getInstance().registerPropertiesStrategy(propertiesStrategy);
            }
            catch (Exception e) {
                log.error("Failed to register Sleuth Hystrix Concurrency Strategy", e);
            }
        }
        private void logCurrentStateOfHystrixPlugins(HystrixEventNotifier eventNotifier,
                                                     HystrixMetricsPublisher metricsPublisher,
                                                     HystrixPropertiesStrategy propertiesStrategy) {
            if (log.isDebugEnabled()) {
                log.debug("Current Hystrix plugins configuration is ["
                        + "concurrencyStrategy [" + this.delegate + "]," + "eventNotifier ["
                        + eventNotifier + "]," + "metricPublisher [" + metricsPublisher + "],"
                        + "propertiesStrategy [" + propertiesStrategy + "]," + "]");
                log.debug("Registering Sleuth Hystrix Concurrency Strategy.");
            }
        }
        @Override
        public <T> Callable<T> wrapCallable(Callable<T> callable) {
            RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
            return new WrappedCallable<>(callable, requestAttributes);
        }
        @Override
        public ThreadPoolExecutor getThreadPool(HystrixThreadPoolKey threadPoolKey,
                                                HystrixProperty<Integer> corePoolSize,
                                                HystrixProperty<Integer> maximumPoolSize,
                                                HystrixProperty<Integer> keepAliveTime, TimeUnit unit,
                                                BlockingQueue<Runnable> workQueue) {
            return this.delegate.getThreadPool(threadPoolKey, corePoolSize, maximumPoolSize,
                    keepAliveTime, unit, workQueue);
        }
        @Override
        public ThreadPoolExecutor getThreadPool(HystrixThreadPoolKey threadPoolKey,
                                                HystrixThreadPoolProperties threadPoolProperties) {
            return this.delegate.getThreadPool(threadPoolKey, threadPoolProperties);
        }
        @Override
        public BlockingQueue<Runnable> getBlockingQueue(int maxQueueSize) {
            return this.delegate.getBlockingQueue(maxQueueSize);
        }
        @Override
        public <T> HystrixRequestVariable<T> getRequestVariable(
                HystrixRequestVariableLifecycle<T> rv) {
            return this.delegate.getRequestVariable(rv);
        }
        static class WrappedCallable<T> implements Callable<T> {
            private final Callable<T> target;
            private final RequestAttributes requestAttributes;
            public WrappedCallable(Callable<T> target, RequestAttributes requestAttributes) {
                this.target = target;
                this.requestAttributes = requestAttributes;
            }
            @Override
            public T call() throws Exception {
                try {
                    RequestContextHolder.setRequestAttributes(requestAttributes);
                    return target.call();
                }
                finally {
                    RequestContextHolder.resetRequestAttributes();
                }
            }
        }
    }
    
  • 相关阅读:
    8.2
    Telnet远程控制协议
    2020/6/29
    HCIA VRP基础命令(二)
    HCIA VRP基础命令(一)
    解决ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock'报错问题
    nginx配置文件nginx.conf
    nginx服务器搭建
    FTP服务器
    NFS
  • 原文地址:https://www.cnblogs.com/jinit/p/14826282.html
Copyright © 2020-2023  润新知