Spring Cloud之Ribbon转发请求头(header参数)_justlpf的专栏-CSDN博客

标签: | 发表时间:2021-04-03 17:53 | 作者:
出处:https://blog.csdn.net

目录

简介

1.自定义RestTemplate

2.将MyRestTemplate注册为Bean

3.构建spring拦截器

4.构建拦截器配置类

5.controller调用

简介

使用spring cloud的ribbon组件可以实现对下游微服务的负载均衡调度,但是官方ribbon是没有header转发功能的,这里我们在ribbon的restTemplate基础上,自定义实现header的转发功能。

1.自定义RestTemplate

      package com.cloud.base.config.ribbon;

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.client.ClientHttpRequest;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.web.client.*;

import java.io.IOException;
import java.net.URI;
import java.util.*;

import static feign.Util.checkNotNull;

/**
 * @author langpf 2019/2/19
 */
public class MyRestTemplate extends RestTemplate {
    private final Map<String, List<String>> headers = new LinkedHashMap<>();

    @Nullable
    @Override
    protected <T> T doExecute(URI url, @Nullable HttpMethod method, @Nullable RequestCallback requestCallback,
                              @Nullable ResponseExtractor<T> responseExtractor) throws RestClientException {

        Assert.notNull(url, "URI is required");
        Assert.notNull(method, "HttpMethod is required");
        ClientHttpResponse response = null;
        try {
            ClientHttpRequest request = createRequest(url, method);

            // lpf: 添加headers
            HttpHeaders myHeaders = request.getHeaders();
            addAllHeaders(myHeaders);

            if (requestCallback != null) {
                requestCallback.doWithRequest(request);
            }
            response = request.execute();
            handleResponse(url, method, response);
            return (responseExtractor != null ? responseExtractor.extractData(response) : null);
        }
        catch (IOException ex) {
            String resource = url.toString();
            String query = url.getRawQuery();
            resource = (query != null ? resource.substring(0, resource.indexOf('?')) : resource);
            throw new ResourceAccessException("I/O error on " + method.name()
                    + " request for \"" + resource + "\": " + ex.getMessage(), ex);
        }
        finally {
            if (response != null) {
                response.close();
            }
        }
    }

    public void header(String name, String... values) {
        checkNotNull(name, "header name");
        if (values == null || (values.length == 1 && values[0] == null)) {
            headers.remove(name);
        } else {
            List<String> headers = new ArrayList<>(Arrays.asList(values));
            this.headers.put(name, headers);
        }
    }

    private void addAllHeaders(HttpHeaders myHeaders) {
        for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
            String key = entry.getKey();
            List<String> values = entry.getValue();
            myHeaders.addAll(key, values);
        }
    }
}

2.将MyRestTemplate注册为Bean

下面代码一般放在SpringBoot工程的启动类中。

      /**
 * 让restTemplate具备Ribbon负载均衡的能力。
 * 由于使用feign, 弃用该方式
 */
@Bean(name="myRestTemplate")
@LoadBalanced
MyRestTemplate restTemplate() {
	return new MyRestTemplate();
}

3.构建spring拦截器

      package com.cloud.base.interceptor.ribbon;

import com.alibaba.fastjson.JSONObject;
import com.cloud.base.config.ribbon.MyRestTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

// @Component("ribbonInterceptor1")
public class RibbonInterceptor implements HandlerInterceptor {
    private static final Logger log = LoggerFactory.getLogger(RibbonInterceptor.class);

    private MyRestTemplate myRestTemplate;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, 
                             Object handler) throws Exception {
        String lpfId = request.getHeader("lpf");

        if (myRestTemplate == null) {  //解决service为null无法注入问题
            BeanFactory factory = 
              WebApplicationContextUtils.getRequiredWebApplicationContext(request.getServletContext());
            myRestTemplate = (MyRestTemplate) factory.getBean("myRestTemplate");
        }

        myRestTemplate.header("lpf", lpfId);

        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) throws Exception {
        // TODO Auto-generated method stub;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, 
                              Object handler, Exception ex)
            throws Exception {
        // TODO Auto-generated method stub;
    }
}

4.构建拦截器配置类

      package com.cloud.base.config;

import com.cloud.base.interceptor.ribbon.RibbonInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * 拦截器配置类
 */
@Configuration
public class WebMvcSessionConfigurer implements WebMvcConfigurer {
    // @Autowired
    // RibbonInterceptor ribbonInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 多个拦截器组成一个拦截器链
        // addPathPatterns 用于添加拦截规则
        // excludePathPatterns 用于排除拦截
        // old: new RedisSessionInterceptor()
        // registry.addInterceptor(ribbonInterceptor).addPathPatterns("/**");
        registry.addInterceptor(new RibbonInterceptor()).addPathPatterns("/**");
    }
    
}

5.controller调用

通过controller调用ribbon时会自动转发header

      package com.cloud.controller;

import com.cloud.base.config.ribbon.MyRestTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.*;

import java.util.Map;

import static com.cloud.base.constant.Constants.SPRING_DATA_SRV;
import static com.cloud.base.constant.Constants.SPRING_SIDECAR_SRV_URL;

/**
 * ribbon调用方式, 参考博客: https://www.jianshu.com/p/470a30f493cf
 * @author langpf 2019/2/19
 */
@RestController
public class RibbonController {
    @Autowired
    MyRestTemplate myRestTemplate;

    /**
     * ribbon -- get请求
     */
    @RequestMapping("ribbonDataSrvHi")
    public String ribbonDataSrvHi() {
        // myRestTemplate.headForHeaders()
        return myRestTemplate.getForEntity(SPRING_DATA_SRV + "hi", String.class).getBody();
    }

    /**
     * ribbon -- get请求
     */
    @RequestMapping("ribbonGetHi")
    public String ribbonGetHi() {
        return myRestTemplate.getForEntity(SPRING_DATA_SRV + "hi", String.class).getBody();
    }

    /**
     * ribbon -- get请求
     * http://localhost:10232/python-user
     */
    @RequestMapping("python-user")
    public String pythonUser() {
        // return myRestTemplate.getForEntity("http://spring-sidecar-python-server/getUser", String.class).getBody();
        return myRestTemplate.getForEntity(SPRING_SIDECAR_SRV_URL + "getUser", String.class).getBody();
    }

    /**
     * ribbon -- post请求
     */
    @RequestMapping(value = "model/serving", method = RequestMethod.POST)
    public String modelServing(@RequestBody HttpEntity entity) {
        return myRestTemplate.postForEntity(SPRING_SIDECAR_SRV_URL + "model/serving", entity, String.class).getBody();
    }

}

 

相关 [spring cloud ribbon] 推荐:

为Spring Cloud Ribbon配置请求重试(Camden.SR2+)

- - 程序猿DD
下面的例子,实现了对服务名为 hello-service的 /hello接口的调用. 由于 RestTemplate被 @LoadBalanced修饰,所以它具备客户端负载均衡的能力,当请求真正发起的时候,url中的服务名会根据负载均衡策略从服务清单中挑选出一个实例来进行访问. 大多数情况下,上面的实现没有任何问题,但是总有一些意外发生,比如:有一个实例发生了故障而该情况还没有被服务治理机制及时的发现和摘除,这时候客户端访问该节点的时候自然会失败.

Spring Cloud之Ribbon转发请求头(header参数)_justlpf的专栏-CSDN博客

- -
1.自定义RestTemplate. 2.将MyRestTemplate注册为Bean. 3.构建spring拦截器. 5.controller调用. 使用spring cloud的ribbon组件可以实现对下游微服务的负载均衡调度,但是官方ribbon是没有header转发功能的,这里我们在ribbon的restTemplate基础上,自定义实现header的转发功能.

大话 Spring Cloud

- - IT瘾-dev
研究了一段时间spring boot了准备向spirng cloud进发,公司架构和项目也全面拥抱了Spring Cloud. 在使用了一段时间后发现Spring Cloud从技术架构上降低了对大型系统构建的要求,使我们以非常低的成本(技术或者硬件)搭建一套高效、分布式、容错的平台,但Spring Cloud也不是没有缺点,小型独立的项目不适合使用.

Spring Cloud限流详解 | Spring Cloud|周立

- -
限流往往是一个绕不开的话题. 本文详细探讨在Spring Cloud中如何实现限流. Zuul上实现限流是个不错的选择,只需要编写一个过滤器就可以了,关键在于如何实现限流的算法. 常见的限流算法有漏桶算法以及令牌桶算法. https://www.cnblogs.com/LBSer/p/4083131.html,写得通俗易懂,你值得拥有,我就不拽文了.

Spring Cloud Kubernetes指南

- -
当我们构建微服务解决方案时,SpringCloud和Kubernetes都是最佳解决方案,因为它们为解决最常见的挑战提供组件. 但是,如果我们决定选择Kubernetes作为我们的解决方案的主要容器管理器和部署平台,我们仍然可以主要通过SpringCloudKubernetes项目使用SpringCloud的有趣特性.

Spring Cloud 快速入门

- - IT瘾-tuicool
Spring Cloud 是一套完整的微服务解决方案,基于 Spring Boot 框架,准确的说,它不是一个框架,而是一个大的容器,它将市面上较好的微服务框架集成进来,从而简化了开发者的代码量. 本课程由浅入深带领大家一步步攻克 Spring Cloud 各大模块,接着通过一个实例带领大家了解大型分布式微服务架构的搭建过程,最后深入源码加深对它的了解.

Deploy the spring cloud project using jenkins

- - Telami
先简单记录下Jenkins部署maven聚合工程要点. Root pom配置成项目根目录的pom.xml. maven命令单独install 欲构建的项目. 选项后可跟随{groupId}:{artifactId}或者所选模块的相对路径(多个模块以逗号分隔). 表示同时处理选定模块所依赖的模块. 表示同时处理依赖选定模块的模块.

Spring Cloud Gateway(限流) | Wind Mt

- -
限流可以保障我们的 API 服务对所有用户的可用性,也可以防止网络攻击. 一般开发高并发系统常见的限流有:限制总并发数(比如数据库连接池、线程池)、限制瞬时并发数(如 nginx 的 limit_conn 模块,用来限制瞬时并发连接数)、限制时间窗口内的平均速率(如 Guava 的 RateLimiter、nginx 的 limit_req 模块,限制每秒的平均速率);其他还有如限制远程接口调用速率、限制 MQ 的消费速率.

快速突击 Spring Cloud Gateway

- - 掘金后端
认识 Spring Cloud Gateway. Spring Cloud Gateway 是一款基于 Spring 5,Project Reactor 以及 Spring Boot 2 构建的 API 网关,是 Spring Cloud 微服务生态的主要组件之一. Spring Cloud Gateway 主要负责接口请求的路由分发,并且支持对请求的安全验证,流量监控和流量控制等扩展操作.

Spring Cloud Gateway2.0实践报告

- - 掘金后端
你的点赞就是对我最大的支持. 原创:小姐姐味道(微信公众号ID:xjjdog),欢迎分享,转载请保留出处. 本文将从知识拓扑讲起,谈一下api网关的功能,以及spring cloud gateway的使用方法. 一、知识拓扑 (使用和原理) 二、网关的作用 三、Predicate,路由匹配 四、Filter,过滤器编写 五、自定义过滤器 六、常见问题 复制代码.