欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringCloud中分析講解Feign組件添加請求頭有哪些坑梳理

 更新時間:2022年06月21日 09:33:33   作者:沙礫_  
在spring?cloud的項目中用到了feign組件,簡單配置過后即可完成請求的調用。又因為有向請求添加Header頭的需求,查閱了官方示例后,就覺得很簡單,然后一頓操作之后調試報錯...下面我們來詳細了解

按官方修改的示例:

#MidServerClient.java
import feign.Param;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@FeignClient(value = "edu-mid-server")
public interface MidServerClient {
    @RequestMapping(value = "/test/header", method = RequestMethod.GET)
    @Headers({"userInfo:{userInfo}"})
    Object headerTest(@Param("userInfo") String userInfo);
}

提示錯誤:

java.lang.IllegalArgumentException: method GET must not have a request body.

分析

通過斷點debug發(fā)現feign發(fā)請求時把userInfo參數當成了requestBody來處理,而okhttp3會檢測get請求不允許有body(其他類型的請求哪怕不報錯,但因為不是設置到請求頭,依然不滿足需求)。

查閱官方文檔里是通過Contract(Feign.Contract.Default)來解析注解的:

Feign annotations define the Contract between the interface and how the underlying client should work. Feign's default contract defines the following annotations:

AnnotationInterface TargetUsage
@RequestLineMethodDefines the HttpMethod and UriTemplate for request. Expressions, values wrapped in curly-braces {expression} are resolved using their corresponding @Param annotated parameters.
@ParamParameterDefines a template variable, whose value will be used to resolve the corresponding template Expression, by name.
@HeadersMethod, TypeDefines a HeaderTemplate; a variation on a UriTemplate. that uses @Param annotated values to resolve the corresponding Expressions. When used on a Type, the template will be applied to every request. When used on a Method, the template will apply only to the annotated method.
@QueryMapParameterDefines a Map of name-value pairs, or POJO, to expand into a query string.
@HeaderMapParameterDefines a Map of name-value pairs, to expand into Http Headers
@BodyMethodDefines a Template, similar to a UriTemplate and HeaderTemplate, that uses @Param annotated values to resolve the corresponding Expressions.

從自動配置類找到使用的是spring cloud的SpringMvcContract(用來解析@RequestMapping相關的注解),而這個注解并不會處理解析上面列的注解

@Configuration
public class FeignClientsConfiguration {
	@Bean
	@ConditionalOnMissingBean
	public Contract feignContract(ConversionService feignConversionService) {
		return new SpringMvcContract(this.parameterProcessors, feignConversionService);
	}

解決

原因找到了:spring cloud使用了自己的SpringMvcContract來解析注解,導致默認的注解解析方式失效。 解決方案自然就是重新解析處理feign的注解,這里通過自定義Contract繼承SpringMvcContract再把Feign.Contract.Default解析邏輯般過來即可(重載的方法是在SpringMvcContract基礎上做進一步解析,否則Feign對RequestMapping相關對注解解析會失效)

代碼如下(此處只對@Headers、@Param重新做了解析):

#FeignCustomContract.java
import feign.Headers;
import feign.MethodMetadata;
import feign.Param;
import org.springframework.cloud.openfeign.AnnotatedParameterProcessor;
import org.springframework.cloud.openfeign.support.SpringMvcContract;
import org.springframework.core.convert.ConversionService;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.*;
import static feign.Util.checkState;
import static feign.Util.emptyToNull;
public class FeignCustomContract extends SpringMvcContract {
    public FeignCustomContract(List<AnnotatedParameterProcessor> annotatedParameterProcessors, ConversionService conversionService) {
        super(annotatedParameterProcessors, conversionService);
    }
    @Override
    protected void processAnnotationOnMethod(MethodMetadata data, Annotation methodAnnotation, Method method) {
        //解析mvc的注解
        super.processAnnotationOnMethod(data, methodAnnotation, method);
        //解析feign的headers注解
        Class<? extends Annotation> annotationType = methodAnnotation.annotationType();
        if (annotationType == Headers.class) {
            String[] headersOnMethod = Headers.class.cast(methodAnnotation).value();
            checkState(headersOnMethod.length > 0, "Headers annotation was empty on method %s.", method.getName());
            data.template().headers(toMap(headersOnMethod));
        }
    }
    @Override
    protected boolean processAnnotationsOnParameter(MethodMetadata data, Annotation[] annotations, int paramIndex) {
        boolean isMvcHttpAnnotation = super.processAnnotationsOnParameter(data, annotations, paramIndex);
        boolean isFeignHttpAnnotation = false;
        for (Annotation annotation : annotations) {
            Class<? extends Annotation> annotationType = annotation.annotationType();
            if (annotationType == Param.class) {
                Param paramAnnotation = (Param) annotation;
                String name = paramAnnotation.value();
                checkState(emptyToNull(name) != null, "Param annotation was empty on param %s.", paramIndex);
                nameParam(data, name, paramIndex);
                isFeignHttpAnnotation = true;
                if (!data.template().hasRequestVariable(name)) {
                    data.formParams().add(name);
                }
            }
        }
        return isMvcHttpAnnotation || isFeignHttpAnnotation;
    }
    private static Map<String, Collection<String>> toMap(String[] input) {
        Map<String, Collection<String>> result =
                new LinkedHashMap<String, Collection<String>>(input.length);
        for (String header : input) {
            int colon = header.indexOf(':');
            String name = header.substring(0, colon);
            if (!result.containsKey(name)) {
                result.put(name, new ArrayList<String>(1));
            }
            result.get(name).add(header.substring(colon + 1).trim());
        }
        return result;
    }
}
#FeignCustomConfiguration.java
import feign.Contract;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.openfeign.AnnotatedParameterProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.ConversionService;
import java.util.ArrayList;
import java.util.List;
@Configuration
public class FeignCustomConfiguration {
    @Autowired(required = false)
    private List<AnnotatedParameterProcessor> parameterProcessors = new ArrayList<>();
    @Bean
    @ConditionalOnProperty(name = "feign.feign-custom-contract", havingValue = "true", matchIfMissing = true)
    public Contract feignContract(ConversionService feignConversionService) {
        return new FeignCustomContract(this.parameterProcessors, feignConversionService);
    }

改完馬上進行新一頓的操作, 看請求日志已經設置成功,響應OK!:

請求: {"type":"OKHTTP_REQ","uri":"/test/header","httpMethod":"GET","header":"{"accept":["/"],"userinfo":["{"userId":"sssss","phone":"13544445678],"x-b3-parentspanid":["e49c55484f6c19af"],"x-b3-sampled":["0"],"x-b3-spanid":["1d131b4ccd08d964"],"x-b3-traceid":["9405ce71a13d8289"]}","param":""}

響應 {"type":"OKHTTP_RESP","uri":"/test/header","respStatus":0,"status":200,"time":5,"header":"{"cache-control":["no-cache,no-store,max-age=0,must-revalidate"],"connection":["keep-alive"],"content-length":["191"],"content-type":["application/json;charset=UTF-8"],"date":["Fri,11Oct201913:02:41GMT"],"expires":["0"],"pragma":["no-cache"],"x-content-type-options":["nosniff"],"x-frame-options":["DENY"],"x-xss-protection":["1;mode=block"]}"}

feign官方鏈接

spring cloud feign 鏈接

(另一種實現請求頭的方式:實現RequestInterceptor,但是存在hystrix線程切換的坑)

到此這篇關于SpringCloud中分析講解Feign組件添加請求頭有哪些坑梳理的文章就介紹到這了,更多相關SpringCloud Feign組件內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Java用itextpdf導出PDF方法(通俗易懂)

    Java用itextpdf導出PDF方法(通俗易懂)

    因為項目需要導出PDF文件,所以去找了一下能夠生成PDF的java工具,這篇文章主要給大家介紹了關于Java用itextpdf導出PDF的相關資料,文中介紹的方法通俗易懂,需要的朋友可以參考下
    2023-07-07
  • java中staticclass靜態(tài)類詳解

    java中staticclass靜態(tài)類詳解

    這篇文章主要介紹了java中staticclass靜態(tài)類詳解,具有一定借鑒價值,需要的朋友可以了解下。
    2017-12-12
  • SpringBoot數據訪問的實現

    SpringBoot數據訪問的實現

    本文主要介紹了SpringBoot數據訪問的實現,引入各種xxxTemplate,xxxRepository來簡化我們對數據訪問層的操作,感興趣的可以了解一下
    2023-11-11
  • Spring @Configuration注解及配置方法

    Spring @Configuration注解及配置方法

    這篇文章主要介紹了Spring @Configuration注解及配置方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-04-04
  • java語言與平臺基礎知識點

    java語言與平臺基礎知識點

    在本篇文章里小編給大家整理的是一篇關于java語言與平臺基礎知識點內容,有需要的朋友們跟著學習下。
    2019-11-11
  • IDEA2023.3.4開啟SpringBoot項目的熱部署(圖文)

    IDEA2023.3.4開啟SpringBoot項目的熱部署(圖文)

    本文使用的開發(fā)工具是idea,使用的是springboot框架開發(fā)的項目,配置熱部署,可以提高開發(fā)效率,文中通過圖文介紹的非常詳細,需要的朋友們下面隨著小編來一起學習學習吧
    2024-02-02
  • springboot整合freemarker詳解

    springboot整合freemarker詳解

    本篇文章主要介紹了springboot整合freemarker詳解,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-05-05
  • Springboot源碼 TargetSource解析

    Springboot源碼 TargetSource解析

    這篇文章主要介紹了Springboot源碼 TargetSource解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-08-08
  • 淺談java安全編碼指南之死鎖dead lock

    淺談java安全編碼指南之死鎖dead lock

    java中為了保證共享數據的安全性,我們引入了鎖的機制。有了鎖就有可能產生死鎖。死鎖的原因就是多個線程鎖住了對方所需要的資源,然后現有的資源又沒有釋放,從而導致循環(huán)等待的情況。通常來說如果不同的線程對加鎖和釋放鎖的順序不一致的話,就很有可能產生死鎖。
    2021-06-06
  • 5分鐘搞定java單例模式

    5分鐘搞定java單例模式

    單例模式(Singleton?Pattern)是?Java?中最簡單的設計模式之一。這種類型的設計模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對象的最佳方式,本文給大家介紹下java單例模式的相關知識,感興趣的朋友一起看看吧
    2022-03-03

最新評論