最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringCloud項(xiàng)目中Feign組件添加請(qǐng)求頭所遇到的坑及解決

 更新時(shí)間:2023年04月26日 10:47:44   作者:沙礫  
這篇文章主要介紹了SpringCloud項(xiàng)目中Feign組件添加請(qǐng)求頭所遇到的坑及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

前言

在spring cloud的項(xiàng)目中用到了feign組件,簡(jiǎn)單配置過后即可完成請(qǐng)求的調(diào)用。

又因?yàn)橛邢蛘?qǐng)求添加Header頭的需求,查閱了官方示例后,就覺得很簡(jiǎn)單,然后一頓操作之后調(diào)試報(bào)錯(cuò)...

按官方修改的示例:

#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);
}

提示錯(cuò)誤:

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

分析

通過斷點(diǎn)debug發(fā)現(xiàn)feign發(fā)請(qǐng)求時(shí)把userInfo參數(shù)當(dāng)成了requestBody來處理,而okhttp3會(huì)檢測(cè)get請(qǐng)求不允許有body(其他類型的請(qǐng)求哪怕不報(bào)錯(cuò),但因?yàn)椴皇窃O(shè)置到請(qǐng)求頭,依然不滿足需求)。

查閱官方文檔里是通過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.

從自動(dòng)配置類找到使用的是spring cloud的SpringMvcContract(用來解析@RequestMapping相關(guān)的注解),而這個(gè)注解并不會(huì)處理解析上面列的注解

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

解決

原因找到了

spring cloud使用了自己的SpringMvcContract來解析注解,導(dǎo)致默認(rèn)的注解解析方式失效。

解決方案自然就是重新解析處理feign的注解,這里通過自定義Contract繼承SpringMvcContract再把Feign.Contract.Default解析邏輯般過來即可(重載的方法是在SpringMvcContract基礎(chǔ)上做進(jìn)一步解析,否則Feign對(duì)RequestMapping相關(guān)對(duì)注解解析會(huì)失效)

代碼如下(此處只對(duì)@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);
    }
    ···

改完馬上進(jìn)行新一頓的操作, 看請(qǐng)求日志已經(jīng)設(shè)置成功,響應(yīng)OK!:

請(qǐng)求:{"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":""}

響應(yīng){"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 鏈接

(另一種實(shí)現(xiàn)請(qǐng)求頭的方式:實(shí)現(xiàn)RequestInterceptor,但是存在hystrix線程切換的坑)

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java-Java5.0注解全面解讀

    Java-Java5.0注解全面解讀

    這篇文章主要介紹了Java-Java5.0注解全面解讀,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • java身份證合法性校驗(yàn)工具類實(shí)例代碼

    java身份證合法性校驗(yàn)工具類實(shí)例代碼

    這篇文章主要給大家介紹了關(guān)于java身份證合法性校驗(yàn)工具類的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • Spring Boot配置過濾器的2種方式示例

    Spring Boot配置過濾器的2種方式示例

    這篇文章主要給大家介紹了關(guān)于Spring Boot配置過濾器的2種方式,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Spring Boot具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • SpringCloud Webflux過濾器增加header傳遞方式

    SpringCloud Webflux過濾器增加header傳遞方式

    這篇文章主要介紹了SpringCloud Webflux過濾器增加header傳遞方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • 基于JavaMail的常用類詳細(xì)介紹

    基于JavaMail的常用類詳細(xì)介紹

    以下是對(duì)JavaMail的常用類進(jìn)行了詳細(xì)分析的介紹,需要的朋友可以過來參考下
    2013-09-09
  • Java多線程工具篇BlockingQueue的詳解

    Java多線程工具篇BlockingQueue的詳解

    今天小編就為大家分享一篇關(guān)于Java多線程工具篇BlockingQueue的詳解,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2019-03-03
  • java實(shí)現(xiàn)發(fā)牌小程序

    java實(shí)現(xiàn)發(fā)牌小程序

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)發(fā)牌小程序,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-11-11
  • Java/Android 實(shí)現(xiàn)簡(jiǎn)單的HTTP服務(wù)器

    Java/Android 實(shí)現(xiàn)簡(jiǎn)單的HTTP服務(wù)器

    這篇文章主要介紹了Java/Android 如何實(shí)現(xiàn)簡(jiǎn)單的HTTP服務(wù)器,幫助大家更好的進(jìn)行功能測(cè)試,感興趣的朋友可以了解下
    2020-10-10
  • Java實(shí)現(xiàn)讀取TXT和CSV文件內(nèi)容

    Java實(shí)現(xiàn)讀取TXT和CSV文件內(nèi)容

    這篇文章主要為大家詳細(xì)介紹了如何利用Java語言實(shí)現(xiàn)讀取TXT和CSV文件內(nèi)容的功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下
    2023-02-02
  • java8列表中通過stream流根據(jù)對(duì)象屬性去重的三種方式

    java8列表中通過stream流根據(jù)對(duì)象屬性去重的三種方式

    這篇文章主要介紹了java8列表中通過stream流根據(jù)對(duì)象屬性去重的三種方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-08-08

最新評(píng)論

石河子市| 灵台县| 青州市| 大新县| 鸡西市| 泰宁县| 大余县| 大庆市| 长岭县| 蒲江县| 隆化县| 桃江县| 浦城县| 浦北县| 商水县| 阆中市| 英吉沙县| 高安市| 兴城市| 东平县| 兴安盟| 九江县| 大冶市| 福泉市| 独山县| 石渠县| 涪陵区| 普宁市| 伊通| 娄烦县| 铜川市| 原阳县| 博爱县| 泽州县| 乡城县| 连城县| 张家川| 遵化市| 禹城市| 策勒县| 株洲县|