OpenFeign——请求其他服务时传递token信息

news2025/4/3 12:25:31

文章目录

  • 前言
  • 准备
  • 流程初测
    • 定义nacos-product子服务
    • 定义服务的消费方 cloudalibaba-openfeign-server
    • 初步测试
    • 结论
  • 设置cloudalibaba-openfeign-server中的feign
  • 总结

前言

在实际开发过程中,服务与服务之间都会有比较频繁的通信操作。其次不同用户所需要查询的数据信息不同,此时为了区别不同的用户操作信息,就需要使用到token令牌机制。

之前的博客 GateWay——向其他服务传递参数数据(思路) 中,已经说了在gateway进行token解析和传递下级服务的操作思路和实现过程。

接下来,说明使用openfeign时,传递token的思路。

准备

准备两个服务cloudalibaba-openfeign-servernacos-product
这两个服务的用处为:

  • nacos-product:请求子服务,对外暴露接口。
  • cloudalibaba-openfeign-server 请求主服务,做主要的业务处理,会使用openfeign调用nacos-product服务的暴露接口。

流程初测

定义nacos-product子服务

主要的暴露接口如下所示:

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;

@RestController
public class TestController {
    @Value("${server.port}")
    private String port;

    @RequestMapping("/product/getProduct/{id}")
    public String getOrder(@PathVariable("id") String id) {

        // 获取 header 中的数据
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = servletRequestAttributes.getRequest();
        String token = request.getHeader("x-client-token-user");

        return "this is product services,port:"+port+"\t id="+id+" \t token = "+token;
    }
}

定义服务的消费方 cloudalibaba-openfeign-server

编写一个请求接口,在接口中模拟gateway设定token,并使用openfeign调用nacos-product子服务的指定暴露接口,查看nacos-product子服务中能否获取对应的token信息。

其中cloudalibaba-openfeign-server接口如下所示:

import linkpower.servive.IOrderService;
import org.apache.tomcat.util.http.MimeHeaders;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;

@RestController
public class OrderController {

    Logger log = LoggerFactory.getLogger(OrderController.class);

    @Autowired
    private IOrderService oserService;

    @RequestMapping("/test/{id}")
    public String getOrder(@PathVariable("id") String id) throws Exception {
        log.info("----getOrder---- id={}",id);

        setRequestHeaderToken();

        return oserService.getOrder(id);
    }

    /**
     * 模拟 gateway
     * 将用户登录的token信息,写入request中
     * @throws Exception
     */
    private void setRequestHeaderToken() throws Exception {
        // 设置 token 值,模拟 gateway 设置请求信息
        // 上下文获取 request 对象
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = servletRequestAttributes.getRequest();
        Class<? extends HttpServletRequest> requestClass = request.getClass();
        // 获取  org.springframework.web.context.request.ServletRequestAttributes.request 属性
        Field requestField = requestClass.getDeclaredField("request");
        requestField.setAccessible(true);
        // 获取实际对象值
        Object requestObj = requestField.get(request);
        Field coyoteRequestField = requestObj.getClass().getDeclaredField("coyoteRequest");
        coyoteRequestField.setAccessible(true);
        Object coyoteRequestObj = coyoteRequestField.get(requestObj);

        Field headersField = coyoteRequestObj.getClass().getDeclaredField("headers");
        headersField.setAccessible(true);
        MimeHeaders headersObj = (MimeHeaders)headersField.get(coyoteRequestObj);
        headersObj.removeHeader("x-client-token-user");
        headersObj.addValue("x-client-token-user").setString("xiangjiao  token   6666");
        log.info("设定token信息成功");
    }
}

调用fengn接口,并指定feign的fallback处理类

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

@FeignClient(value = "nacos-product",fallback = IOrderServiceFallback.class)
public interface IOrderService {

    @RequestMapping("/product/getProduct/{id}")
    public String getOrder(@PathVariable("id") String id);
}
import org.springframework.stereotype.Component;

/**
 * IOrderService  降级处理类
 */
//org.springframework.beans.factory.BeanCreationException:
// Error creating bean with name 'cn.linkpower.service.IOrderService':
// FactoryBean threw exception on object creation; nested exception is java.lang.IllegalStateException:
// No fallback instance of type class cn.linkpower.service.IOrderServiceFallback found for
// feign client nacos-product
@Component
public class IOrderServiceFallback implements IOrderService {

    /**
     * 针对  getOrder的降级处理
     * @param id
     * @return
     */
    @Override
    public String getOrder(String id) {
        return "fallback --- IOrderServiceFallback";
    }
}

初步测试

debug启动两个服务,都注册至nacos中,请求cloudalibaba-openfeign-server中的接口,观察nacos-product子服务是否能获取到cloudalibaba-openfeign-server接口中设定的token信息。

http://localhost:8500/test/2

断点调试,在cloudalibaba-openfeign-server中能够看到设置token成功。
在这里插入图片描述
继续下一步,查看nacos-product是否可以获取到。
在这里插入图片描述

结论

发现模拟gateway设置浏览器请求token信息,但在子服务中并没有获取到。
【原因:】feign是一个新的请求,与原来的请求不是同一个!!!

设置cloudalibaba-openfeign-server中的feign

增加一个配置类,主要功能是将原请求对象中的header参数值,设置到新的请求对象中。逻辑代码如下所示:

import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;

/**
 *
 */
public class MyFeignConfig implements RequestInterceptor {
    private static final Logger log = LoggerFactory.getLogger(MyFeignConfig.class);
    @Override
    public void apply(RequestTemplate requestTemplate) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes != null) {
            HttpServletRequest request = attributes.getRequest();
            Enumeration<String> headerNames = request.getHeaderNames();
            String name;
            // 将原有请求中的header,数据转移至新的请求中
            if (headerNames != null) {
                while(headerNames.hasMoreElements()) {
                    name = (String)headerNames.nextElement();
                    String values = request.getHeader(name);
                    if (!name.equalsIgnoreCase("content-length")) {
                        requestTemplate.header(name, new String[]{values});
                    }
                }
            }

        }
    }
}

@FeignClient中增加配置类引用,如下所示:

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

@FeignClient(value = "nacos-product",
	fallback = IOrderServiceFallback.class,
	configuration = MyFeignConfig.class)
//@FeignClient(value = "nacos-product",fallback = IOrderServiceFallback.class)
public interface IOrderService {

    @RequestMapping("/product/getProduct/{id}")
    public String getOrder(@PathVariable("id") String id);
}

重启cloudalibaba-openfeign-server服务,再次请求测试:

http://localhost:8500/test/2

在这里插入图片描述
能够成功获取!

总结

思路就是增加一个openfeign的配置类,在程序业务代码调用feign时,会经过事先配置的类,进行原request对象中header属性,拷贝至 新的RestTemplate 的请求对象中。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/703929.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【正点原子STM32连载】 第四十七章 SRAM实验 摘自【正点原子】STM32F103 战舰开发指南V1.2

1&#xff09;实验平台&#xff1a;正点原子stm32f103战舰开发板V4 2&#xff09;平台购买地址&#xff1a;https://detail.tmall.com/item.htm?id609294757420 3&#xff09;全套实验源码手册视频下载地址&#xff1a; http://www.openedv.com/thread-340252-1-1.html# 第四…

使用inno打包程序流程

1:配置iss文件 ​​​​​​​ 2编译 3.生成安装包文件安装

浅谈建筑项目中的智能照明系统的设计与研究

【摘要】&#xff1a;建筑智能照明工程中智能照明控制系统发展迅速&#xff0c;具有舒适性和节能性两方面优势。智能照明控制系统已经处于模块化高速发展阶段&#xff0c;如今更好的控制方案成为制约系统发展的瓶颈。文章在研究了国内外智能照明系统的基础上&#xff0c;从照明…

【CSS】nth:children以及浏览器内核webkit使用(滚动条样式修改)

&#x1f609;博主&#xff1a;初映CY的前说(前端领域) ,&#x1f4d2;本文核心&#xff1a;nth:children以及浏览器中的webkit使用 前言&#xff1a;在页面的编写中使用了多个标签通常有需求去处理下特殊的样式&#xff0c;我们常见做法是给我们的标签加上一个类或者通过标签选…

【微服务】什么是微服务?-- 全面了解微服务架构

What is Microservices — Edureka 您有没有想过&#xff0c;什么是微服务以及扩展行业如何与它们集成&#xff0c;同时构建应用程序以满足客户的期望&#xff1f; 要了解什么是微服务&#xff0c;您必须了解如何将单体应用程序分解为独立打包和部署的小型微型应用程序。本文将…

力扣 -- 91.解码方法

题目链接&#xff1a;91. 解码方法 - 力扣&#xff08;LeetCode&#xff09; 以下是用动态规划的思想解决这道题目&#xff0c;如果对动态规划五部曲的含义还不是很清楚的老铁可以看看本专栏的第一题动规(10条消息) 力扣 -- 746. 使用最小花费爬楼梯_KOBE 0824 BRYANT的博客-…

软件测试编写文档模板【附文档模板】

一、测试岗位必备的文档 在一个常规的软件测试流程中&#xff0c;会涉及到测试计划、测试方案、测试用例、测试报告的编写&#xff0c;这些文档也是软件测试岗位必须掌握的文档类型。 1、测试计划 测试计划是组织管理层面的文件&#xff0c;从组织管理的角度对一次测试活动进…

华为OD机试真题 Python实现【最小的调整次数】【2023Q1 100分】

目录 一、题目描述二、输入描述三、输出描述四、补充说明五、解题思路六、Python算法源码七、效果展示1、输入2、输出3、说明 一、题目描述 有一个特异性的双端队列&#xff0c;该队列可以从头部或尾部添加数据&#xff0c;但是只能从头部移出数据。 小A依次执行2n个指令往队…

uboot详解(嵌入式学习)

uboot详解 概念详解扩展Windows的“uboot” 概念 U-Boot&#xff08;Unified Bootloader&#xff09;是一个开源的嵌入式系统引导加载程序&#xff0c;也是一种通用的引导加载程序。它主要用于嵌入式系统的启动过程&#xff0c;负责初始化硬件设备、加载操作系统内核和启动应用…

Android Studio 使用 Build Variants 配置测试/正式环境域名等字段

拿测试环境域名和正式环境域名举例&#xff1a;在项目调试和发版过程中可以通过频繁地注释和解开注释来切换正式环境域名和测试环境域名&#xff0c;但此方法过于繁琐&#xff1b;所以可以使用Android Studio的Build Variants根据切换环境来替我们执行切换环境的操作。 在项目…

《HelloGitHub》第 87 期

兴趣是最好的老师&#xff0c;HelloGitHub 让你对编程感兴趣&#xff01; 简介 HelloGitHub 分享 GitHub 上有趣、入门级的开源项目。 https://github.com/521xueweihan/HelloGitHub 这里有实战项目、入门教程、黑科技、开源书籍、大厂开源项目等&#xff0c;涵盖多种编程语言 …

可视化对讲广播电话可以用在哪里

可视化对讲广播电话可以用在哪里 可视化对讲广播电话&#xff1a;无处不在的沟通利器 【工地现场】 在矗立的高楼上&#xff0c;工地上忙碌的工人们使用着可视化对讲广播电话。借助高清画面和清晰音频&#xff0c;工作人员可以实时观察工地情况&#xff0c;更好地协调工作&a…

【【51单片机实现LED点阵屏幕和动画显示】】

LED点阵屏幕和驱动代码 我们先搞清楚&#xff17;&#xff14;HC&#xff15;&#xff19;&#xff15;的原理 &#xff53;&#xff46;&#xff52; 特殊功能寄存器声明 &#xff53;&#xff42;&#xff49;&#xff54; 特殊位声明 就举个例子&#xff0c;我们在之前的…

Linux后台运行Python脚本

Linux后台运行Python脚本命令&#xff1a; nohup python webui.py > myout.file 2>&1 &nohup&#xff1a;nohup命令用于不挂断地运行命令python&#xff1a;执行python代码的命令webui.py: python程序脚本源代码>: 打印程序输出信息到指定日志文件中myout.fi…

[vue]使用Element--Tree 树形控件使用props解决自定义slot-scope=“{ node, data }“的对象问题

在未用props定义的情况下&#xff0c;slot-scope"{ node, data }"解析data对象只有data含有lable和children才能识别出内容和子节点 当我获取的数据如下&#xff0c;没有lable和children&#xff0c;使用的是name和childList&#xff0c;如下图所示&#xff1a; 注意…

设计必备的矢量插画素材,这几个网站超齐全。

分享几个设计必备的矢量插画、插图素材网站&#xff0c;建议收藏~ 菜鸟图库 https://www.sucai999.com/searchlist/bianpingchahua----all-0-1.html?vNTYxMjky 菜鸟图库是一个素材非常丰富的网站&#xff0c;这里面涵盖了平面、电商、UI、图片、高清背景、插画、视频、音频等…

【新星计划】技术博客写作技巧经验分享

序言 写技术博客需要一定的专业知识和写作技巧&#xff0c;它是一个很好的方式来分享你的经验和知识&#xff0c;同时也是一个展示你的专业能力和建立自己品牌的机会。 以下是一些准备和建议&#xff0c;希望可以帮助你写出有用和有吸引力的技术博客&#xff1a; 写在前面 我报…

使用Elasticsearch进行word,excel,PDF的全文检索 windows实现 超完整(ingest-attachment实现)

首先要明确的一点就是Elasticsearch的版本要和ingest-attachment的版本一致&#xff0c;要不然没办法安装。然后还有一点JAVA版本要在11以上 先说说原理吧&#xff0c;其实就是将文件base64编码&#xff0c;然后再用插件读取文件内容并保存到es中。 1.如果你的版本是JAVA1.8的…

win11系统升级后QT的程序识别套件失败解决

解决方法&#xff1a; QTCreator的配置文件存放位置:C:\Users\%USERNAME%\AppData\Roaming\QtProject。删除这个文件夹下的文件&#xff0c;重启QT就会自动识别kits套件初始化信息等 就是QT我配置的颜色也消失了按照如下步骤重新配置后再次重启QT即可 这个方法导致我QT 上配…

苹果开发者账号续费流程及苹果开发者账号续费流程及下架处理

当开发者的苹果开发者账号即将到期时&#xff0c;可能会面临以下问题&#xff1a;“如何查看开发者账号剩余时间&#xff1f;”和“如何进行续费&#xff1f;”本文将详细解答这些问题。 如何查询账号过期时间&#xff1f; 如果距离开发者账号过期时间不到一个月&#xff0c;您…