在微服务中使用Fegin进行内部调用无法获取用户信息

这种是因为我们在A服务调用B服务时,并不能把当前线程的用户信息带过去,因为SecurityContextHolder.getContext().getAuthentication()取值,是取的自己本地线程的。Feign集成Hystrix默认是关闭Hystrix的,只有在配置文件中设置feign.hystrix.enabled=true才会开启Hystrix。开启Hystrix后feign之间的方法调用就会默认启动新的线程执行,和主程序不在一个线程中,因此如果上下文中存在ThreadLocal变量,在该方法中就失效了。

一、不开启服务降级熔断

可以直接使用SecurityContextHolder.getContext().getAuthentication();获取当前token并传递给下游服务

@Configuration
public class MyOAuthRequestInterceptor implements RequestInterceptor {

	 @Override
    public void apply(RequestTemplate template) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            
        if (authentication instanceof JwtAuthenticationToken){
            JwtAuthenticationToken jwtAuthenticationToken = (JwtAuthenticationToken) authentication;
            String tokenValue = jwtAuthenticationToken.getToken().getTokenValue();
            template.header(HttpHeaders.AUTHORIZATION,
				String.format("%s %s", OAuth2AccessToken.To
<think>好的,我现在需要解释远程调用的两种实现方式:一种是Go语言基于原生的HTTP请求,另一种是Java基于Spring Cloud Feign。首先,我得确保自己理解这两个概念,然后组织语言让用户能够清楚明白。 首先,关于远程调用的基本概念。远程调用允许不同服务之间通过网络通信进行交互。用户提到的场景是返回用户名称,所以可能涉及客户端向服务端发送请求,服务端处理并返回用户名。 接下来是Go语言的原生HTTP请求实现。我需要回忆一下Go的标准库,比如net/http包。处理HTTP请求通常需要创建客户端,构造请求,发送请求,处理响应。例如,使用http.NewRequest创建GET请求,设置URL和参数,然后使用http.Client的Do方法发送请求,最后读取响应体并解析结果。这部分需要详细说明步骤,可能还要提到JSON解析,比如使用encoding/json包来解码响应数据。 然后是Java的Spring Cloud Feign部分。Feign是一个声明式的HTTP客户端,简化了远程调用的编码。需要提到Spring Cloud的集成,如何通过接口和注解定义服务,比如@FeignClient注解,指定服务名和路径。Feign内部会处理负载均衡(通过Ribbon)和服务发现(通过Eureka),这些可能需要稍微提一下,但重点在于Feign使用方式。例如,定义一个接口,方法上使用@RequestMapping或@GetMapping注解,参数可能通过@PathVariable或@RequestParam传递。调用时像调用本地方法一样,Feign生成实现类处理HTTP请求和响应解析。 比较两者的差异也很重要。Go的原生实现更底层,需要手动处理更多细节,但灵活;而Feign通过抽象让代码更简洁,依赖Spring Cloud生态,适合微服务架构。性能方面,Go可能更高效,但Feign的便利性在复杂系统中更有优势。 还要注意用户提到的返回用户名称的具体例子,可能需要分别给出两个语言的代码示例片段。比如Go中使用http.Get或构造请求,处理JSON响应;Java中定义Feign客户端接口,自动转换响应为对象。 需要检查是否有理解错误的地方。比如Feign是否必须配合服务发现,或者是否可以有其他配置方式。确保提到的步骤和代码示例正确,特别是注解和包的使用。另外,确认术语准确,比如“声明式”是否正确描述了Feign的特点。 最后,组织回答结构,先介绍远程调用的概念,再分别详细说明两种实现方式,最后对比它们的优缺点,帮助用户理解不同场景下的选择。</think>以下是对两种远程调用实现方式的对比说明: 一、远程调用核心概念 远程调用(RPC)是分布式系统中不同服务间的通信方式,通过封装网络通信细节,让开发者像调用本地方法一样调用远程服务。示例场景:客户端调用服务端接口获取用户名称。 二、Go原生HTTP实现 1. 实现原理 直接使用net/http标准库进行HTTP通信,需手动处理请求/响应序列化 2. 典型代码示例 ```go // 服务端 func getUserName(w http.ResponseWriter, r *http.Request) { userId := r.URL.Query().Get("userId") // 业务逻辑处理... json.NewEncoder(w).Encode(map[string]string{"name": "张三"}) } // 客户端 func remoteGetName(userId string) string { resp, err := http.Get("http://api.example.com/user?userId=" + userId) if err != nil { /* 错误处理 */ } defer resp.Body.Close() var result struct{ Name string } json.NewDecoder(resp.Body).Decode(&result) return result.Name } ``` 3. 特点 - 无额外依赖 - 需要手动处理: - 请求参数拼接 - 响应状态码判断 - 连接池管理 - JSON序列化/反序列化 - 性能调优空间大 三、Java Spring Cloud Feign实现 1. 实现原理 基于声明式接口的HTTP客户端,整合了以下组件: - 服务发现(Eureka/Nacos) - 负载均衡(Ribbon) - 熔断降级(Hystrix) - 自动序列化(Jackson) 2. 典型代码示例 ```java // 服务声明接口 @FeignClient(name = "user-service", path = "/api/user") public interface UserServiceClient { @GetMapping("/name") String getUserName(@RequestParam("userId") String userId); } // 自动生成的实现类处理: // 1. 服务发现 // 2. 负载均衡 // 3. HTTP请求构造 // 4. 响应解析 // 客户端调用 @Autowired private UserServiceClient userService; public String showUserName(String userId) { return userService.getUserName(userId); // 如同本地调用 } ``` 3. 特点 - 声明式编程:接口即契约 - 自动集成Spring Cloud生态 - 内置重试机制和熔断器 - 支持多种编码器(JSON/XML等) - 注解驱动配置 四、核心差异对比 | 特性 | Go原生实现 | Spring Cloud Feign | |--------------------|-------------------------|-------------------------| | 代码复杂度 | 高(需手动处理细节) | 低(声明式接口) | | 学习曲线 | 平缓(标准库即可) | 陡峭(需掌握Spring生态) | | 性能 | 更高(无额外抽象层) | 稍低(存在代理开销) | | 微服务支持 | 需自行集成 | 开箱即用(服务发现/负载均衡) | | 适用场景 | 简单调用/性能敏感场景 | 复杂微服务架构 | | 协议支持 | 支持任意HTTP交互 | 主要面向RESTful规范 | 五、选择建议 - 小型项目/性能优先:推荐Go原生实现 - 大型微服务体系:推荐Feign+Spring Cloud组合 - 混合架构场景:Go服务可通过API网关接入Spring Cloud体系 两种方式本质上都是基于HTTP协议的通信,主要区别在于抽象层级和生态整合程度。实际选型需结合团队技术栈和项目规模综合考虑。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刘个Java

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值