【springcloud】解決使用feign調用服務 header參數傳遞的問題

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.後記

這個問題當時搞了我一下午,看來對這些框架原理還不是特別熟,不過能解決這個,還是有點小收穫滴。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章