本文為博主原創,轉載請注明出處:
spring cloud 服務組件之間通過feign 的方式請求,會攜帶很少的基礎類型的消息頭參數,比如Content-Type等,但不會攜帶自定義或指定的請求頭參數,
在實際的開發過程中,需要對從網關或其他服務組件使用feign請求時,攜帶原始請求的請求頭,並做一些基礎校驗和業務校驗等。
1.如果要在服務使用feign請求過程中,攜帶請求的原始請求頭信息時,需要是請求處於同一個線程,這樣才能在使用feign請求時,才能獲取到當前請求的
原始請求頭。在使用feignClient請求時,默認是會新建線程,去執行服務請求,如果新建線程,則會解析不到原始請求的請求頭。需要對hystrix 進行一下的配置,
才能保證處於同一個線程當中。
hystrix默認使用多線程管理請求連接池,從主線程到發送基於hystrix的feign請求線程已不在同一個線程內。可通過設置策略區分是否為同一個線程。
strategy: SEMAPHORE 基於信號量,前后會保持同一個線程。strategy: THREAD 基於異步線程,前后為不同的線程
hystrix: command: default: execution: timeout: enabled: true isolation: strategy: SEMAPHORE thread: timeoutInMilliseconds: 60000
添加以上配置,可以對feignClient 進行消息頭的配置,
2.由於feign 請求底層是通過 RestTemplate 進行請求,Feign 支持請求攔截器,在發送請求前,可以對發送的模板進行操作,例如設置請求頭等屬性,
自定請求攔截器需要實現 feign.RequestInterceptor 接口,該接口的方法 apply 有參數 template ,該參數類型為 RequestTemplate,我們可以根據實際情況對請求信息進行調整,
對消息頭的封裝,可以使用攔截器進行一下的封裝:
package com.imooc.homepage.config; import feign.RequestInterceptor; import feign.RequestTemplate; 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; @Configuration public class FeignConfiguration implements RequestInterceptor{ @Override public void apply(RequestTemplate template) { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder .getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); // 對消息頭進行配置 Enumeration<String> headerNames = request.getHeaderNames(); if (headerNames != null) { while (headerNames.hasMoreElements()) { String name = headerNames.nextElement(); String values = request.getHeader(name); template.header(name, values); } } // 對請求體進行配置 Enumeration<String> bodyNames = request.getParameterNames(); StringBuffer body =new StringBuffer(); if (bodyNames != null) { while (bodyNames.hasMoreElements()) { String name = bodyNames.nextElement(); String values = request.getParameter(name); body.append(name).append("=").append(values).append("&"); } } if(body.length()!=0) { body.deleteCharAt(body.length()-1); template.body(body.toString()); } } }
3.對FeignClient添加以上配置,進行請求:
@FeignClient(value = "client-homepage-course", fallback = CourseClientHystrix.class,configuration = FeignConfiguration.class) public interface CourseClient { @RequestMapping(value = "/homepage-course/get/courses", method = RequestMethod.POST) List<CourseInfo> getCourseInfos(@RequestBody CourseInfosRequest request); }
在服務中配置 FeignConfiguration 時,上面的代碼示例是通過 RequestContextHolder.getRequestAttributes() 解析到當前請求頭的參數,
RequestContextHolder是基於ThreadLocal實現的,所以需要保證請求是一直處於同一個線程當中,hystrix強大在於是支持此擴展操作的。
另一種解決方案:由於所解析的模塊沒有添加spring-web相關的依賴配置,無法使用 RequestContextHolder ,使用 過濾器過濾出當前
線程中的請求頭,並保存到ThreadLocal 中,在 FeignConfiguration 中解析 保存在ThreadLocal中的消息頭參數,然后設置消息頭給RestTemplate.
