Feign动态设置header

OpenFeign调用微服务使用RequestInterceptor或@RequestHeader传递http请求头信息 记录:391 场景:基于Spring Cloud OpenFeign调用微服务Restful接口时,请求头从A服务传递到B服务,可以使用RequestInterceptor接口或者@RequestHeader注解传递请求头信息。 阅读详情

背景需求

springmvc 可以直接通过拦截器Interceptor和过滤器filter拦截请求头header,从而获取必要的验证信息作为我们业务逻辑服务。比如权限验证,多租户的权限范围等等。

但是在springcloud中微服务的调用其实最终也是远程调用了http,那么能不能在客户端调用的时候发给服务端的header中添加自定义的信息呢,比如业务线ID或者auhtor信息等等进而和springmvc的业务逻辑部分统一避免额外的代码实现。

Feign设置header目前有两种方式

1.实现拦截器RequestInterceptor 统一处理
2.手工创建Feignclient配置拦截器
3.RequestInterceptor +ThreadLocal实现动态传参

拦截器统一处理

我们可以直接在接口的interface的公共包中加入如下配置,这样同样的调用都会经过这个拦截器处理,进而实现统一的header处理。

import feign.RequestInterceptor;
import feign.RequestTemplate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;


@Slf4j
public class HeaderInterceptor implements RequestInterceptor {

		@Value("${feign.contract-op.businessId:sys}")
    private String businessId;
    @Override
    public void apply(RequestTemplate requestTemplate) {
        log.info("requestTemplate.header get value feign.contract-op.businessId: {}= {} ",ContractRequestHeaders.BUSINESS_ID,businessId);
        if(businessId!=null && !"sys".equals(businessId)){
            requestTemplate.header("businessId", businessId);
        }
    }
}

接口类这里直接配置为configuration,这样每次调用时它都执行一次HeaderInterceptor 拦截器

@FeignClient(
        url = "${feign.contract-op.url:https://192.168.1.1:50003/contract-op-service}/billInfo",
        name = "contractOpClient",
        contextId = "billInfoClient",configuration = ContractFeignConfiguration.class
)
public interface BillInfoClient {

    @ApiOperation(value = "分页")
    @GetMapping
    PageInfo<BillInfoListResponse> page(@SpringQueryMap @Validated BillInfoListRequest searchRequest);

}

如果我们不在这个configuration 配置,而是HeaderInterceptor 加上@Configuration注解,那么它会对所有全局的feignclien都会加上这个参数处理。

手工创建

也有文章提供了Feign.builder()手工创建的方式

 @Autowired
    private ObjectFactory<HttpMessageConverters> messageConverters;


    public DeviceSeriesClient deviceSeriesClient(String businessId) {
        DeviceSeriesClient deviceSeriesClient = Feign.builder().client(client)
                .encoder(new SpringEncoder(this.messageConverters))
                .decoder(new OptionalDecoder(new ResponseEntityDecoder(new SpringDecoder(this.messageConverters))))
                .contract(new SpringMvcContract())
                .requestInterceptor(template -> template.header(HEADER_KEY,   businessId))
                .target(DeviceSeriesClient.class, "https://192.168.1.1:50001/user-service/series");
        return deviceSeriesClient;
    }

这里encoder,decoder它改成了feign默认使用的是SpringEncoder,但是我这里Feign调用服务报错:Load balancer does not have available server for client:xxx
可能是我这边使用nacos作为服务发现和注册中心,获取到的url是注册中信的地址无法进行调用。

RequestInterceptor +ThreadLocal实现动态传参

由于提供方的代码是搭好版本的,只能调用方自行实现,因此在以上都不
我想到的另一个办法,
1.配置全局移除已经存在的header中的key值,防止该key多值数组
2.利用filter拦截前端请求过来的业务ID存入ThreadLocal,然后放入到对应feignclient的requestTemplate中

这样不管是前端还是feign客户端都可以统一在这个地方进行业务参数的加入,同时也支持不同业务参数根据前端需要动态的传递不同值的问题。

import feign.RequestInterceptor;
import feign.RequestTemplate;
import io.deepblueai.cloud.robotics.webapi.exception.ApiException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.filter.GenericFilterBean;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;


@Component
@Slf4j
public class RequestParameterFilter extends GenericFilterBean implements RequestInterceptor {

    static ThreadLocal<String> localVar = new ThreadLocal<>();

    @Override
    public void apply(RequestTemplate requestTemplate) {

        requestTemplate.removeHeader("businessId");
        String businessId =localVar.get();
        if(businessId!=null){
            log.info("feign RequestInterceptor businessId = {}",businessId);
            requestTemplate.header("businessId", businessId);
        }
        localVar.remove();
        log.info("feign RequestInterceptor apply end");
    }


	// 放行swagger-ui相应的请求路径
    public static final String[] ALLOW_URL = {"/**/swagger**","/**/webjars/**",
            "/**/swagger-resources/**","/**/v2/api-docs**","/**/csrf","/**/error"};

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
        if (servletRequest instanceof HttpServletRequest) {

            HttpServletRequest request = (HttpServletRequest) servletRequest;
            String uri = request.getRequestURI();

            log.info("request uri :" + uri);

            if (isAllow(uri)) {
                filterChain.doFilter(servletRequest, response);
                return;
            }

            String businessId = request.getHeader(ContractRequestHeaders.BUSINESS_ID);
            log.info("Mvc header uri={},businessId={}",request.getRequestURI(),businessId);
            if (businessId == null) {
                log.error("businessId is null");
                throw new ApiException(ExceptionEnum.business_ID_NULL_ERROR.getCode(), "businessId不能为空");
            }else {
                /*Map<String, Object> map = new HashMap<String, Object>(16);
                map.put("businessId", businessId);
                RequestParameterWrapper requestParameterWrapper = new RequestParameterWrapper(request, map);*/
                log.info("Mvc ParameterFilter uri={},businessId={}",request.getRequestURI(),request.getParameter("businessId"));
                //feign header set localval
                localVar.set(businessId);

                //filterChain.doFilter(requestParameterWrapper, response);
            }
			filterChain.doFilter(servletRequest, response);

        }
    }

    public static boolean isAllow(String url) {
        boolean flag = false;
        for (String pattern : ALLOW_URL) {
            AntPathMatcher matcher = new AntPathMatcher();
            if (matcher.match(pattern, url)) {
                flag = true;
                break;
            }
        }
        return flag;
    }


    @Override
    public  void destroy() {
        //执行两次,非feign业务也执行一次
        localVar.remove();
    }
}

因为spring的http是使用的线程池,因此使用ThreadLocal时每次使用完要清理下,避免重复使用线程会互相残留问题。

关于feign调用传递header的解决方法 我现在用feign来实现内部系统的方法调用,但有一个问题,使用国际化的时候语言传递不了,因为在header上。 下面贴一下解决方案:@Bean public RequestInterceptor headerInterceptor() { return new RequestInterceptor() { @Override 阅读详情

相关推荐

Spring Cloud Feign传输Header,并保证多线程情况下也适用

Spring Cloud Feign传输Header,并保证多线程情况下也适用 一、现象 微服务在生产中,常遇到需要把 header 传递到下一子服务的情况(如服务A访问服务B的接口,需要传递header),网上大多数的方案是实现 RequestInterceptor 接口,在重写方法中,把 header 填进 Feign 的请求中。我们先按这种方式,简单实现代码如下: 1、继承RequestInterceptor 服务A新建类,继承 RequestInterceptor,把 header 设置到请求中,注

hehe的博客 7651

Spring-Cloud Feign设置Header信息

Feign 调用接口是经常会忘header信息,再次介绍两种忘header里面添加信息的方式: 1. 通过直接在请求上,或者在类上添加Headers的注解 @Headers({"Content-Type: application/json","Accept: application/json",Accept {contentType}}) @PostMapping(value = "/car...

谈少华的博客 5961

汽车TARA分析实战:从威胁建模到安全需求落地的完整指南

在汽车电子电气系统开发中,威胁分析与风险评估(TARA)是确保功能安全与网络安全的核心方法论。其原理在于通过结构化的流程,系统性地识别资产、分析威胁场景并评估风险,旨在将安全理念前置,从设计源头规避风险。这一过程的技术价值在于将模糊的安全担忧转化为可量化、可追溯的工程需求,从而指导资源精准投放,是符合ISO 26262和ISO/SAE 21434标准要求的关键实践。其应用场景贯穿智能汽车从概念设计到系统开发的各个阶段,尤其对于涉及自动驾驶、智能座舱、车云通信等复杂功能的域控制器开发至关重要。本文聚焦于TAR

weixin_42706667的博客 303

SpringCloud 中feign在服务间传递header

在上述示例中,通过自定义的HeaderInterceptor拦截器类,在请求发出之前添加了名为"headerName",值为"headerValue"的header。最后,在MyService中调用MyFeignClient的getSomeData方法,Feign会自动将指定的header传递到服务端。总结起来,使用Feign传递header的方法有两种:通过自定义拦截器来添加header,或者通过@RequestHeader注解来手动指定需要传递的header。根据具体需求和场景选择适合的方式。

牛肉胡辣汤 4205

深度解析快递柜管理系统的C++实现:设计与实现

本文详细介绍了一个基于C++的快递柜管理系统的设计与实现,包括系统需求分析、架构设计、数据库设计、关键功能模块实现和测试与验证。通过详细的代码示例和理论分析,读者可以全面了解如何开发一个完整的快递柜管理系统。希望本文能够为读者在实际项目开发中提供有价值的参考。

m0_57781768的博客 713

用MCP扩展Cursor的5种神奇用法:从文件操作到网页抓取实战

本文深入探讨了如何利用MCP(Model Context Protocol)扩展Cursor AI编程助手,解锁五种高效实用场景。从文件系统操作、网页内容抓取,到数据库查询、Figma设计稿对接,乃至构建自定义MCP服务器,文章通过实战案例展示了如何将Cursor从代码编辑器升级为能理解并操作工作环境的智能助手,显著提升开发效率与自动化水平。

weixin_29231027的博客 315

Feign设置动态header

Feign动态设置Header Feign设置全局header Feign 调用接口是经常会忘header信息,再次介绍两种忘header里面添加信息的方式: 1.通过直接在请求上,或者在类上添加Headers的注解 @Headers({"Content-Type: application/json","Accept: application/json",Accept {contentType}}) @PostMapping(value = "/card-blank/batch-create") Respo

zhaoyang10的专栏 2万+

Altera下载器驱动配置:手把手教程(从零实现)

详解Altera USB-Blaster驱动安装全过程,从设备识别到软件配置一步一图,解决常见连接问题,确保开发下载器正常工作,适合初学者快速上手FPGA下载调试。

weixin_35751194的博客 986

Feign动态设置Header

来源 Feign调用接口: /** * @author Liangzhifeng * date: 2018/9/13 */ public interface UserInfoFeignClient { /** * 根据token获取用户信息 * @param token * @return */ @RequestMapping(val...

技术人员 3060

Supermind量化实战:我如何给双均线策略加上“止损”和“仓位管理”,让回测收益更稳健

本文详细介绍了如何在Supermind平台上为双均线策略添加止损和仓位管理模块,以提升量化交易的稳健性。通过Python实现动态止损和智能仓位管理,策略的年化收益率从12.3%提升至15.8%,最大回撤从58.7%降至22.4%,Sharpe比率显著提高。这些实战技巧适用于量化交易爱好者,帮助他们在黑天鹅行情中保持收益稳定。

weixin_42567752的博客 361

Pointnet++环境配置(Windows11和ubuntu)及训练教程

PS:前两行命令是数据处理的命令,主要是进行数据读取和生成相应的训练数据格式,在Ubuntu上是正常运行的,在Windows上运行会失败,无法生成训练用的数据格式,所以最好在Ubuntu上训练,如果一定要用Windows,可以ubuntu上生成数据格式在导到Windows上,数据生成不需要安装torch。通过anaconda配置的环境,在官网找的命令安装的,版本是2.1.0+cu118。训练命令:我使用的pycharm,直接在pycharm中打开终端,运行命令。Python版本:3.7。

AIcurator的博客 2558

java 动态添加header_设置Feign的Header信息

设置Feign的Header信息两种方式1.在方法参数前面添加@RequestHeader注解@PostMapping(value = "/getStuDetail")public ReturnInfo getStudentDetail(@RequestBody Map map,@RequestHeader(name = "id") String id);使用@RequestHeader(name...

weixin_30341121的博客 1437

DeepSeek邮件管理全攻略

DeepSeek邮件助手是一款高效的邮件处理工具,提供智能分类、撰写、回复和任务自动化功能。通过API调用或多智能体系统,它能自动分类邮件意图、生成专业回复并优化邮件内容。核心功能包括智能过滤、会议安排和任务提醒,支持与主流邮箱服务集成。提供精准提示词模板,帮助用户快速生成得体邮件,提升工作效率。适合个人和企业使用,通过简单配置即可实现邮件处理自动化。

Genio_Wang的博客 180

spring cloud feign 动态设置header

1、这是最简单的一个方法,但是需要对每个调用都一一添加,就是使用@RequestHeader注解添加参数到请求头中去 @FeignClient(name = "capability-register", fallback = ApiServiceClientFallBack.class ) public interface ApiServiceClient { @GetMapping...

varyall的专栏 6127

2026年佰维存储数字IC笔试试卷带答案

建立时间是有效时钟沿到来前,输入数据必须稳定保持的最短时间。保持时间是有效时钟沿到来后,输入数据必须继续稳定保持的最短时间。

Open 103

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

Spring Boot中使用Feign设置请求头Header的值

背景 使用Feign调用外部接口时,需要在Headers中带一个如下的参数: 按照网上的说法,有通过注解@Header的方式; 有在@RequestMapping中设置header属性的方式.; 有通过拦截器实现header值的填充. 亲自尝试过之后,第一种方法不起作用,第二种方法不支持动态参数(发现一篇博客,这篇博客的方案二讲了如何使用动态参数,但没有亲自尝试.). 第三种会拦截所有的请求,...

fengpojian的博客 5389

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

使用Feign时如何设置Feign的Header信息

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_34167819的博客 6694

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

设置Feign的Header信息

设置Feign的Header信息 两种方式 1.在方法参数前面添加@RequestHeader注解 @PostMapping(value = "/getStuDetail") public ReturnInfo getStudentDetail(@RequestBody Map map,@RequestHeader(name = "id") String id); 使用@RequestHeader...

weixin_30843605的博客 182

feign设置 header basicauth_踩了一个Spring Cloud Feign添加自定义Header的坑,分享给大家

需求背景需求背景最近有个需求,是对接某个运动APP的Api开放平台用户授权业务。文中以两个API为例:1、获取token场景:用户在授权⻚页⾯面点击授权后,⻚页⾯面会跳转到合作⽅方提供的redirect_url,合作⽅方通过跳转传回的code换取token,完成认证和授权。Header附加参数:Authorization:Basic base64(AppKey:AppSecret) `注意:Bas...

weixin_39901558的博客 1591

spring cloud关于feign client的调用对象列表参数、设置header参数、多环境动态参数试配...

spring cloud关于feign client的调用 1、有些场景接口参数需要传对象列表参数 2、有些场景接口设置设置权限等约定header参数 3、有些场景虽然用的是feign调用,但并不会走eureka,比如调用外网www.baidu.com等的接口,需要进行多环境试配 示例如下: server controller端: @...

weixin_30258901的博客 855

请求header_踩了一个Spring Cloud Feign添加自定义Header的坑,分享给大家

需求背景需求背景最近有个需求,是对接某个运动APP的Api开放平台用户授权业务。文中以两个API为例:1、获取token场景:用户在授权⻚页⾯面点击授权后,⻚页⾯面会跳转到合作⽅方提供的redirect_url,合作⽅方通过跳转传回的code换取token,完成认证和授权。Header附加参数:Authorization:Basic base64(AppKey:AppSecret) `注意:Bas...

weixin_33632413的博客 1102

优雅配置spring cloud feign的header

本文总结了多种spring cloud feign使用过程中header的处理方式,包括动态header和静态header。

cuiyaocool的博客 900

关于 Feign 的使用中,简单事项

关在前后端 调用 大多数是 json,今天对接第三方免登录授权,对方接口规范非文件上传也要求form表单,先用postman调用,正常返回 后在代码实现 总是302,起初怀疑2点,1授权失败 2、是否postman自动做了重定向所以成功 从第一点入手的,跟源码发现,参数都正常传了,但是header没有值,我用 @RequestHeader("APP_TOKEN"),发现无法传值,就开始琢磨为何header赋值不上 @PostMapping(value = "/test/token",consumes

u010460945的博客 931
上一篇: rabbitMq延迟队列实现
下一篇: Nacos 安装部署
牧竹子
博客等级 码龄17年 572粉丝 233原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值