In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-18 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >
Share
Shulou(Shulou.com)06/02 Report--
This article introduces the knowledge of "how to add custom Header to Spring Cloud Feign". In the operation of actual cases, many people will encounter such a dilemma, so let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!
Background
Recently an interface has been called that requires that the token be passed in the header. Since my project uses feign, you have to find a way to add header to the request in feign.
Solution 1: customize RequestInterceptor
When generating a proxy object for the @ FeignClient annotated interface, there is a paragraph:
Class FeignClientFactoryBean implements FactoryBean, InitializingBean, ApplicationContextAware {@ Override public Object getObject () throws Exception {return getTarget ()} / / getTarget () will eventually call configureUsingConfiguration () protected void configureUsingConfiguration (FeignContext context,Feign.Builder builder) {Map requestInterceptors = context.getInstances (this.contextId, RequestInterceptor.class) If (requestInterceptors! = null) {builder.requestInterceptors (requestInterceptors.values ());}...}
The RequestInterceptor of the spring context is used when the proxy class is generated, and the interceptor is used when the proxy class of @ FeignClient is executed:
Final class SynchronousMethodHandler implements MethodHandler {Request targetRequest (RequestTemplate template) {for (RequestInterceptor interceptor: requestInterceptors) {interceptor.apply (template);} return target.apply (template);}}
So customize your own interceptor and inject it into the spring context, so you can add a custom request header to the context of the request:
@ Servicepublic class MyRequestInterceptor implements RequestInterceptor {@ Override public void apply (RequestTemplate template) {template.header ("my-header", "header");} advantages
It is easy to implement and can be injected using existing interfaces.
Shortcoming
The operation is a global RequestTemplate, so it is difficult to provide different header according to different service parties. Although you can judge different service providers according to uri in template, and then add the corresponding header, there is a lot of configuration information out of thin air, and it is difficult to maintain.
Option 2: add header information to the @ RequestMapping annotation
Now that we've used the openfeign framework, let's find out how openfeign officially solves it (https://github.com/OpenFeign/feign):
/ / openfeign official document public interface ContentService {@ RequestLine ("GET / api/documents/ {contentType}") @ Headers ("Accept: {contentType}") String getDocumentByType (@ Param ("contentType") String type);}
From the above official code example, we can find that our needs can be met by using native API:
@ FeignClient (name = "feign", url = "127.0.0.1 public interface FeignTest 8080") public interface FeignTest {@ RequestMapping (value = "/ test") @ Headers ({"app: test-app", "token: ${test-app.token}"}) String test ();}
However, it is a pity that @ Headers does not take effect, and there is no above two Header information in the generated RequestTemplate. Tracking the code, we found that ReflectFeign prepares the data through the Contract interface when generating the proxy class for the remote service. The reason why the * @ Headers* annotation does not take effect is that the official Contract does not take effect:
Class FeignClientFactoryBean implements FactoryBean, InitializingBean, ApplicationContextAware {protected Feign.Builder feign (FeignContext context) {Feign.Builder builder = get (context, Feign.Builder.class) / / required values .logger (logger) .encoder (get (context) Encoder.class) .decoder (get (context, Decoder.class)) .contract (get (context, Contract.class)) ...}}
For springcloud-openfeign, when creating Feign-related classes, you use the Contract injected in the container:
@ Bean@ConditionalOnMissingBeanpublic Contract feignContract (ConversionService feignConversionService) {return new SpringMvcContract (this.parameterProcessors, feignConversionService);} public class SpringMvcContract extends Contract.BaseContract implements ResourceLoaderAware {@ Override public MethodMetadata parseAndValidateMetadata (Class targetType, Method method) {.... / / notice here that it only takes the RequestMapping annotation RequestMapping classAnnotation = findMergedAnnotation (targetType, RequestMapping.class);. ParseHeaders (md, method, classAnnotation);} return md;}}
At this point, we sort out the whole story:
Openfeign supports adding custom header to methods, using its own annotation @ Headers
Springcloud-openfeign uses the core functionality of openfeign, but the @ Headers annotation is not used
Springcloud uses its own SpringMvcContract to process the requested resource information, which only uses the @ RequestMapping annotation
What we can easily think of is that since the @ RequestMapping annotation has the attribute headers, we can try it.
@ FeignClient (name = "server", url = "127.0.0.1 test-app.token 8080") public interface FeignTest {@ RequestMapping (value = "/ test", headers = {"app=test-app", "token=$ {test-app.token}"}) String test ();}
A hands-on test is available so that we can customize the header information individually for a specific service.
Advantages
The implementation is easier, and you don't even have to implement the interface yourself, you just need to add the corresponding attribute configuration to the relevant annotations.
Shortcoming
Although there is no need to add header to the global request, for the same server, it will be troublesome to add the same header configuration to each @ RequestMapping annotation. Can it be global?
Scenario 3: custom Contract
Through the SpringMvcContract code, it is also easy to find that for class annotations, it only deals with RequestMapping and ignores everything else. So if we redefine our Contract, we can do whatever we want.
For convenience, we directly reuse @ Header of openfeign
For simplicity, we inherit SpringMvcContract directly
Customize your own Contract and inject it into the spring context
/ * for simplicity, we directly inherit SpringMvcContract * / @ Servicepublic class MyContract extends SpringMvcContract {/ * this attribute is to use springcloud config * / private ResourceLoader resourceLoader; @ Override protected void processAnnotationOnClass (MethodMetadata data, Class clz) {/ / reuse the original SpringMvcContract logic super.processAnnotationOnClass (data, clz) / / the following is the new logic (actually using the logic of Contract.Default that comes with openfeign) if (clz.isAnnotationPresent (Headers.class)) {String [] headersOnType = clz.getAnnotation (Headers.class). Value (); Map headers = toMap (headersOnType); headers.putAll (data.template (). Headers ()); data.template (). Headers (null) / / to clear data.template (). Headers (headers);}} private Map toMap (String [] input) {Map result = new LinkedHashMap (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 (1));} result.get (name) .add (resolve (header.substring (colon + 1). Trim ());} return result } private String resolve (String value) {if (StringUtils.hasText (value) & & resourceLoader instanceof ConfigurableApplicationContext) {return ((ConfigurableApplicationContext) this.resourceLoader). GetEnvironment () .innovvePlaceful (value);} return value;} @ Override public void setResourceLoader (ResourceLoader resourceLoader) {this.resourceLoader = resourceLoader / / Note that because SpringMvcContract also uses resourceLoader, you must specify a parser for it, otherwise the placeholder super.setResourceLoader (resourceLoader) will not be parsed;}}
When in use, you can directly configure the interface as header:
@ Headers ({"app: test-app", "token: ${test-app.token}"}) public interface FeignTest {@ RequestMapping (value = "/ test") String test ();} advantages
You can freely define it according to your own needs.
Shortcoming
Customization brings certain learning costs, and because it directly inherits the implementation of spring, it leaves hidden dangers for future upgrades.
Scenario 4: use @ RequestMapping on the interface and add the headers attribute
Smart readers may be able to reflect this at the end of scenario 2: springcloud supports the header of the * @ RequestMapping* annotation, which can be used on classes!
@ FeignClient (name = "feign", url = "127.0.0.1 RequestMapping 8080") @ RequestMapping (value = "/", headers = {"app=test-app", "token=$ {test-app.token}"}) public interface FeignTest {@ RequestMapping (value = "/ test") String test ();} advantages
No customization at all, native support
Shortcoming
Almost nothing. For some students who are not used to using @ RequestMapping annotations on classes, it may be a bit obsessive-compulsive, but it can be ignored.
Think: why didn't you think of liberating the note to the interface definition in the first place?
Mindset, work content problems, rarely use @ RequestMapping on the feign interface
There is no handling of header in the processAnnotationOnClass method in SpringMvcContract, which causes this to be ignored at first
SpringMvcContract is to solve the problem of header above the class in parseAndValidatateMetadata
This is the end of the content of "how to add Custom Header for Spring Cloud Feign". Thank you for reading. If you want to know more about the industry, you can follow the website, the editor will output more high-quality practical articles for you!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.