• feign远程调用时如何在请求头加入数据


    1.先提出问题的解决方案
       通过实现Feign的RequestInterceptor(拦截器)接口,重写里面的apply方法,为RequestTemplate添加自定义的请求头的参数及数据的传入。请求最开始进来的时候,就会进入到这个拦截器中,业务代码中进行远程调用的时候还会进入到这个请求里面来。
    
    1. @Component
    2. public class FeignClientsExtendInterceptor implements RequestInterceptor {
    3. @Override
    4. public void apply(RequestTemplate requestTemplate) {
    5. // 此种方式是线程安全的
    6. ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder
    7. .getRequestAttributes();
    8. // 不为空时取出请求中的header 原封不动的设置到feign请求中
    9. if (null != attributes) {
    10. HttpServletRequest request = attributes.getRequest();
    11. if (null != request) {
    12. // 遍历设置 也可从request取出整个Header 写到RequestTemplate 中
    13. Enumeration headerNames = request.getHeaderNames();
    14. if (headerNames != null) {
    15. while (headerNames.hasMoreElements()) {
    16. String name = headerNames.nextElement();
    17. String values = request.getHeader(name);
    18. requestTemplate.header(name, values);
    19. }
    20. }
    21. }
    22. }
    23. // 处理请求体参数信息
    24. // feign调用get接口的时候,会报出405 Request method ‘POST‘ not supported的错误
    25. // 当你不需要将请求体内的信息也传输过去的,可以通过注释处理请求体信息的代码来解决
    26. // 原因是feign底层发请求的时候,发现请求体带有参数会自动转成post请求。
    27. /*
    28. Enumeration bodyNames = request.getParameterNames();
    29. StringBuilder body = new StringBuilder();
    30. if (bodyNames != null) {
    31. while (bodyNames.hasMoreElements()) {
    32. String name = bodyNames.nextElement();
    33. String values = request.getParameter(name);
    34. body.append(name).append("=").append(values).append("&");
    35. }
    36. }
    37. if (body.length() != 0) {
    38. body.deleteCharAt(body.length() - 1);
    39. requestTemplate.body(body.toString());
    40. }
    41. */
    42. }
    43. }

    2.业务场景(保证后面的请求中,调用者的信息一致)

    (1)消费了MQ消息,发起了远程调用。

            也就是这个时候是没有请求相关的信息的,但是在feign发起请求的时候,需要保证请求头里的信息是当前线程的相关信息,这个时候可以把需要的相关信息放入一个线程副本中去,通过继承RequestContextHolder或者重写一个相似的类,将当前线程的信息放置进去,然后在feign发起远程调用的时候,将所需信息取出来,放入请求头中。

    (2)同一线程

            前端请求时,会在请求头中带上一系列的校验参数,调用我的服务,需要再去调用其他服务。在其他服务中, 需要对请求头中的信息做提取或者校验。

            feign远程调用的时候,底层是对参数进行了封装然后进行请求,是一次新的请求,那么前端传入请求中的头文件信息自然不会被传过去,所以可以通过重写RequestInterceptor,将请求头的信息原封不动的复制进去。

    (3)多线程异步调用其他微服务

            上述重写的代码可能就获取不到主线程的请求信息了,主要原因是:RequestContextHolder来获取request信息,发现异步调用时,主线程结束后,子线程就获取不到request,会报出错误信息。

    解决方式1:

            通过获取到主线程的请求,在前端调用的时候,前端请求会进来,这个时候开启子线程共享,那么在后面的业务执行时,发现异步调用时,主线程结束后,子线程是可以获取request的相关信息的。

    1. ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
    2. // 在上面代码后面开启子线程共享
    3. RequestContextHolder.setRequestAttributes(servletRequestAttributes,true);//设置子线程共享

    解决方式2:

            与(2)同一线程的处理方式类似,将主线程的request和session信息放进ThreadLocal里,透传到子线程再去获取。

  • 相关阅读:
    vue实战项目之vue-cli脚手架搭建过程详解
    软件测试神仙文档,连阿里面试官都说太详细了,搞懂这些直接是P7级
    企业运维 | MySQL关系型数据库在Docker与Kubernetes容器环境中快速搭建部署主从实践
    密码学与信息安全面试题及参考答案(2万字长文)
    Kubernetes:服务与负载均衡
    MVP推荐 丨 2024 FISCO-BCOS官方学习路线 ,一定要看的所有内容,都在这里了!
    软件人和硬件人有啥区别?
    MySQL 用户授权管理及白名单
    db-cdc之mysql 深入了解并使用binlog
    不看你就亏了,最新最全的腾讯,阿里、百度、美团等大厂都在用的Redis实战
  • 原文地址:https://blog.csdn.net/weixin_42218169/article/details/125901794