springcloud解决使用feign调用服务 header参数传递的问题

2022年8月12日10:15:53

1. 遇到的问题

测试人员发现,在用户查看自己的一个收藏功能时,显示用户没有登录。

2.问题原因

收藏服务A的一个功能,方法里面调用了另外一个服务B的接口,由于还没有做单点登录系统,需要在同一个注册中心上注册的服务之间传递header参数里面的一个token,导致服务B里面的方法接受的请求header里面没有token,因此服务B的方法抛出异常【用户未登录】,然后把结果链式传递到了服务A,最终给用户显示【用户未登录】

3.解决思路

方法1.做一个单点登录系统,目前人手不够,还没时间研究研究,

方法2.通过feign调用其他服务的时候,把服务A的header参数传递到服务B( 目前通过2解决掉)

4.步骤

①eureka注册中心上现在有三个服务 :网关gateway-service,用户user-service 收藏collect-service

②前端调用对应的服务其实都是经过了gateway-service,前置过滤器来判断token信息,存储到一次请求HttpServletRequest中了,并把token信息存储到redis里面缓存起来 ,gateway-service中的guolv之后存储token信息逻辑如下:

@Override
	public Object run() throws ZuulException {
		RequestContext ctx = RequestContext.getCurrentContext();
		HttpServletRequest req = ctx.getRequest();
		String token = req.getHeader("token");
		log.info("===========登录令牌 = {}", token);
		if (StringUtils.isNotBlank(token)) {
			String json = stringRedisTemplate.opsForValue().get("token" + token);
			log.info("===========登录用户缓存信息:{}", json);
			if (StringUtils.isNotBlank(json)) {
				ctx.setSendZuulResponse(true);
				ctx.setResponseStatusCode(HttpStatus.SC_OK);
				try {
					ctx.addZuulRequestHeader("USER_REDIS_KEY",
							URLEncoder.encode(JSONObject.toJSONString(json), "UTF-8"));
				} catch (UnsupportedEncodingException e) {
					e.printStackTrace();
				}
				return null;
			}
		}
	
		// 返回错误提示信息
		log.error("===========请求失败401");
		ctx.setSendZuulResponse(false);
		ctx.setResponseStatusCode(HttpStatus.SC_UNAUTHORIZED);
		String responseBody = JSON.toJSON(Result.error(ResponseCode.NO_ACCESS)).toString();
		ctx.setResponseBody(responseBody);
		ctx.getResponse().setContentType("application/json;charset=UTF-8");
		return null;
	}

③由于之前在使用feign调用的其他服务时候,直接使用的对方的服务名来调用,没有经过网关服务,其实想要通过feign之间 的服务调用经过网关,很简单,把服务名都配置成网关服务名即可,让eureka找到gateway-service后,然后让gate-service来帮你找对应的实例 ,collect-service中 feignClient接口如下:

package com.client;

import com.util.Result;
import com.form.UserCollectCheckWxappForm;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;

@FeignClient("gateway-service") //之前这里写的是user-service,换成网关服务gate-service,这样就经过网关了
public interface UserServiceClient {

    // 这里想要调用的服务加上user-service即可
    @PostMapping(value = "user-service/easysale/wxapp/collect/v1/checkHasCollect")
    Result checkHasCollect(UserCollectCheckWxappForm userCollectCheckWxappForm);

}

④collect-service中 配置feign拦截器,使其传递header中token参数

package com.config;

import feign.RequestInterceptor;
import feign.RequestTemplate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;
import java.util.Objects;

@Slf4j
@Configuration
public class FeignConfig implements RequestInterceptor {

    @Override
    public void apply(RequestTemplate requestTemplate) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

        log.info("house-server, attributes:{}",attributes);
        if (Objects.isNull(attributes)) return;

        HttpServletRequest request = attributes.getRequest();
        Enumeration<String> headerNames = request.getHeaderNames();
        log.info("house-server, headerNames:{}",headerNames);
        if (headerNames != null) {
            while (headerNames.hasMoreElements()) {
                String name = headerNames.nextElement();
                String values = request.getHeader(name);
                requestTemplate.header(name, values);
            }
        }
    }
}

⑤还有一点别忘了,在yml文件配置熔断策略,SEMAPHORE,这能保障在一次链路请求中........(其实这里我还也还没搞清楚,后续再聊。。。)

hystrix:
  command:
    default:
      execution:
        isolation:
          strategy: SEMAPHORE
          thread:
            timeoutInMilliseconds: 60000

⑥重启网关服务gateway-service,和collect-service 测试ok,解决测试问题

5.后记

这个问题当时搞了我一下午,看来对这些框架原理还不是特别熟,不过能解决这个,还是有点小收获滴。

  • 作者:阿来小同学
  • 原文链接:https://blog.csdn.net/skybboy/article/details/103080769
    更新时间:2022年8月12日10:15:53 ,共 3482 字。