文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Feign利用自定义注解实现路径转义详解

2024-04-02 19:55

关注

背景

近期由于项目中需要,所以需要通过Feign封装一个对Harbor操作的sdk信息。

在调用的过程中发现,当请求参数中带有"/"时,Feign默认会将"/"当成路径去解析,而不是当成完整的一个参数解析,实例如下

请求路径为:api/v2.0/projects/{projectName}/repositories

注解参数为:@PathVariable("projectName")

正常请求为:api/v2.0/projects/test/repositories

异常路径为:api/v2.0/projects/test/pro/repositories

相信细心的同学已经发现上面的差异了,正常的{projectName}中对应的值为test,而异常的却对应为test/pro,所以当异常的请求打到harbor的机器时,被解析为api/v2.0/projects/test/pro/repositories,所以会直接返回404

以上就是背景了,所以接下来我们讨论一下解决方案

解决方案

首先我们知道springboot中默认是带有几种注释参数处理器的

@MatrixVariableParameterProcessor
@PathVariableParameterProcessor
@QueryMapParameterProcessor
@RequestHeaderParameterProcessor
@RequestParamParameterProcessor
@RequestPartParameterProcessor

因为我们的请求参数是在路径中的,所以默认我们会使用@PathVariableParameterProcessor来标识路径参数,而我们需要转义的参数其实也是在路径中,所以我们先来看一下@PathVariableParameterProcessor是如何实现的

public boolean processArgument(AnnotatedParameterProcessor.AnnotatedParameterContext context, Annotation annotation, Method method) {
        String name = ((PathVariable)ANNOTATION.cast(annotation)).value();
        Util.checkState(Util.emptyToNull(name) != null, "PathVariable annotation was empty on param %s.", new Object[]{context.getParameterIndex()});
        context.setParameterName(name);
        MethodMetadata data = context.getMethodMetadata();
        String varName = '{' + name + '}';
        if (!data.template().url().contains(varName) && !this.searchMapValues(data.template().queries(), varName) && !this.searchMapValues(data.template().headers(), varName)) {
            data.formParams().add(name);
        }
        return true;
    }

其实在源码中,springboot并没有做什么神器的事情,就是获取使用了PathVariable注解的参数,然后再将其添加到fromParams中就可以。

看到这里我们是不是可以想到,既然在这里我们可以拿到对应的参数了,那想做什么事情不都是由我们自己来决定了,接下来说干就干,

首先我们声明一个属于自己的注解,

import org.springframework.core.annotation.AliasFor;

import java.lang.annotation.*;


@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SlashPathVariable {

    
    @AliasFor("name")
    String value() default "";

    
    @AliasFor("value")
    String name() default "";

    
    boolean required() default true;
}

声明完注解后,我们就需要来自定义自己的参数解析器了,首先继承AnnotatedParameterProcessor

import feign.MethodMetadata;
import feign.Util;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.openfeign.AnnotatedParameterProcessor;
import org.springframework.web.bind.annotation.PathVariable;

import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedType;
import java.lang.reflect.Method;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


public class SlashPathVariableParameterProcessor implements AnnotatedParameterProcessor {

    private  static  final Class<SlashPathVariable> ANNOTATION=SlashPathVariable.class;
    @Override
    public Class<? extends Annotation> getAnnotationType() {
        return (Class<? extends Annotation>) ANNOTATION;
    }

    @Override
    public boolean processArgument(AnnotatedParameterContext context, Annotation annotation, Method method) {
        MethodMetadata data = context.getMethodMetadata();
        String name = ANNOTATION.cast(annotation).value();
        Util.checkState(Util.emptyToNull(name) != null, "SlashPathVariable annotation was empty on param %s.", new Object[]{context.getParameterIndex()});
        context.setParameterName(name);
        data.indexToExpander().put(context.getParameterIndex(),this::expandMap);
        return true;
    }

    private String expandMap(Object object) {
        String encode = URLEncoder.encode(URLEncoder.encode(object.toString(), Charset.defaultCharset()), Charset.defaultCharset());
        return encode;
    }
}

可以看到上面的代码,我们获取到自定义注解的参数后,将当前参数添加打Param后,并且为当前参数指定自定义的编码格式。

最后,我们再通过Bean的形式将对应的注解添加到容器中

import feign.Contract;
import org.springframework.cloud.openfeign.AnnotatedParameterProcessor;
import org.springframework.cloud.openfeign.support.SpringMvcContract;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;


@Component
public class SlashBean {

    @Bean
    public Contract feignContract(){
        List<AnnotatedParameterProcessor> processors=new ArrayList<>();
        processors.add(new SlashPathVariableParameterProcessor());
        return new SpringMvcContract(processors);
    }
}

最后我们将上面的参数注解PathVariable换成我们自定义的@SlashPathVariable,就大功告成了

最后

通过以上的形式进行注入的话,会注入到Spring全局,所以在使用的过程中需要考虑是否符合场景

以上就是Feign利用自定义注解实现路径的转义详解的详细内容,更多关于Feign路径的转义的资料请关注编程网其它相关文章!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯