spring boot实现超轻量级网关(反向代理、转发)
在我们的rest服务中,需要暴露一个中间件的接口给用户,但是需要经过rest服务的认证,这是典型的网关使用场景。可以引入网关组件来搞定,但是引入zuul等中间件会增加系统复杂性,这里实现一个超轻量级的网关,只实现请求转发,认证等由rest服务的spring security来搞定。
如何进行请求转发呢? 熟悉网络请求的同学应该很清楚,请求无非就是请求方式、HTTP header,以及请求body,我们将这些信息取出来,透传给转发的url即可。
举例:
/graphdb/** 转发到 Graph_Server/**
获取转发目的地址:
private String createRedictUrl(HttpServletRequest request, String routeUrl, String prefix) {
String queryString = request.getQueryString();
return routeUrl + request.getRequestURI().replace(prefix, "") +
(queryString != null ? "?" + queryString : "");
}
解析请求头和内容
然后从request中提取出header、body等内容,构造一个RequestEntity,后续可以用RestTemplate来请求。
private RequestEntity createRequestEntity(HttpServletRequest request, String url) throws URISyntaxException, IOException {
String method = request.getMethod();
HttpMethod httpMethod = HttpMethod.resolve(method);
MultiValueMap<String, String> headers = parseRequestHeader(request);
byte[] body = parseRequestBody(request);
return new RequestEntity<>(body, headers, httpMethod, new URI(url));
}
private byte[] parseRequestBody(HttpServletRequest request) throws IOException {
InputStream inputStream = request.getInputStream();
return StreamUtils.copyToByteArray(inputStream);
}
private MultiValueMap<String, String> parseRequestHeader(HttpServletRequest request) {
HttpHeaders headers = new HttpHeaders();
List<String> headerNames = Collections.list(request.getHeaderNames());
for (String headerName : headerNames) {
List<String> headerValues = Collections.list(request.getHeaders(headerName));
for (String headerValue : headerValues) {
headers.add(headerName, headerValue);
}
}
return headers;
}
透明转发
最后用RestTemplate来实现请求:
private ResponseEntity<String> route(RequestEntity requestEntity) {
RestTemplate restTemplate = new RestTemplate();
return restTemplate.exchange(requestEntity, String.class);
}
全部代码
以下是轻量级转发全部代码:
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StreamUtils;
import org.springframework.web.client.RestTemplate;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collections;
import java.util.List;
@Service
public class RoutingDelegate {
public ResponseEntity<String> redirect(HttpServletRequest request, HttpServletResponse response,String routeUrl, String prefix) {
try {
// build up the redirect URL
String redirectUrl = createRedictUrl(request,routeUrl, prefix);
RequestEntity requestEntity = createRequestEntity(request, redirectUrl);
return route(requestEntity);
} catch (Exception e) {
return new ResponseEntity("REDIRECT ERROR", HttpStatus.INTERNAL_SERVER_ERROR);
}
}
private String createRedictUrl(HttpServletRequest request, String routeUrl, String prefix) {
String queryString = request.getQueryString();
return routeUrl + request.getRequestURI().replace(prefix, "") +
(queryString != null ? "?" + queryString : "");
}
private RequestEntity createRequestEntity(HttpServletRequest request, String url) throws URISyntaxException, IOException {
String method = request.getMethod();
HttpMethod httpMethod = HttpMethod.resolve(method);
MultiValueMap<String, String> headers = parseRequestHeader(request);
byte[] body = parseRequestBody(request);
return new RequestEntity<>(body, headers, httpMethod, new URI(url));
}
private ResponseEntity<String> route(RequestEntity requestEntity) {
RestTemplate restTemplate = new RestTemplate();
return restTemplate.exchange(requestEntity, String.class);
}
private byte[] parseRequestBody(HttpServletRequest request) throws IOException {
InputStream inputStream = request.getInputStream();
return StreamUtils.copyToByteArray(inputStream);
}
private MultiValueMap<String, String> parseRequestHeader(HttpServletRequest request) {
HttpHeaders headers = new HttpHeaders();
List<String> headerNames = Collections.list(request.getHeaderNames());
for (String headerName : headerNames) {
List<String> headerValues = Collections.list(request.getHeaders(headerName));
for (String headerValue : headerValues) {
headers.add(headerName, headerValue);
}
}
return headers;
}
}
Spring 集成
Spring Controller,RequestMapping里把GET \ POST\PUT\DELETE 支持的请求带上,就能实现转发了。
@RestController
@RequestMapping(GraphDBController.DELEGATE_PREFIX)
@Api(value = "GraphDB", tags = {
"graphdb-Api"
})
public class GraphDBController {
@Autowired
GraphProperties graphProperties;
public final static String DELEGATE_PREFIX = "/graphdb";
@Autowired
private RoutingDelegate routingDelegate;
@RequestMapping(value = "/**", method = {RequestMethod.GET, RequestMethod.POST, RequestMethod.PUT, RequestMethod.DELETE}, produces = MediaType.TEXT_PLAIN_VALUE)
public ResponseEntity catchAll(HttpServletRequest request, HttpServletResponse response) {
return routingDelegate.redirect(request, response, graphProperties.getGraphServer(), DELEGATE_PREFIX);
}
}
作者:Jadepeng
出处:jqpeng的技术记事本--http://www.cnblogs.com/xiaoqi
您的支持是对博主最大的鼓励,感谢您的认真阅读。
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
spring boot实现超轻量级网关(反向代理、转发)的更多相关文章
- 【应用服务 App Service】 App Service Rewrite 实例 - 反向代理转发功能
问题描述 在使用Azure App Service(应用服务)时,有时候需要在不同的站点之间进行跳转,但是希望通过通过访问同一个域名的方式来实现反向代理.如果创建应用时候选择的是Window服务,这时 ...
- SpringCloud微服务笔记-Nginx实现网关反向代理
背景 当前在SpringCloud微服务架构下,网关作为服务的入口尤为重要,一旦网关发生单点故障会导致整个服务集群瘫痪,为了保证网关的高可用可以通过Nginx的反向代理功能实现网关的高可用. 项目源码 ...
- nginx反向代理转发后页面上的js css文件无法加载【原创】
故障现象:nginx做代理转发后,发现页面上的js css文件无法加载,页面样式乱了. 原因:没有配置静态资源 解决js css文件无法加载无法访问的问题 解决办法: 修改配置文件nginx.conf ...
- IIS充当反向代理转发请求到Kestrel
接着上篇博文为ASP.NetCore程序启用SSL的code,这篇将介绍如何用IIS充当反向代理的角色转发请求到Kestrel服务器 介绍 与ASP.NET不同,ASP.netCore使用的是自托管w ...
- Nginx反向代理转发Host设置
默认情况下反向代理是不会转发请求中的Host头部,如果需要转发,则需要配置红色字体表示的选项参数. location /t02 { proxy_set_header Host $host; proxy ...
- nginx证书制作以及配置https并设置访问http自动跳转https(反向代理转发jboss)
nginx证书制作以及配置https并设置访问http自动跳转https 默认情况下ssl模块并未被安装,如果要使用该模块则需要在编译时指定–with-http_ssl_module参数,安装模块依赖 ...
- 【转】Nginx反向代理转发tomcat
http://blog.csdn.net/mlc1218559742/article/details/53117520 最近刚接触nginx,在网上查阅了相关资料,看到最多的形容nginx的词就是反向 ...
- 【Nginx】Nginx反向代理转发Host设置
#事故现场: 服务器A(Nginx服务器):192.168.2.126 服务器B(Web服务器):192.168.2.221 服务器A反向代理服务器B,A配置了upstream为: http { up ...
- Spring Boot @Trasactionl 失效, JDK,CGLIB动态代理
来自: https://www.cnblogs.com/sweetchildomine/p/6978037.html?utm_source=itdadao&utm_medium=referra ...
随机推荐
- 一文看懂Vue3.0的优化
1.源码优化: a.使用monorepo来管理源码 Vue.js 2.x 的源码托管在 src 目录,然后依据功能拆分出了 compiler(模板编译的相关代码).core(与平台无关的通用运行时代码 ...
- day39 Pyhton 并发编程02
一.内容回顾 并发和并行的区别 并发 宏观上是在同时运行的 微观上是一个一个顺序执行 同一时刻只有一个cpu在工作 并行 微观上就是同时执行的 同一时刻不止有一个cpu在工作 什么是进程 一个运行中的 ...
- CTSC2010
星际旅行 https://www.luogu.com.cn/problem/P4189 题目:且每个星球的\(H_i\)大于等于与该星球直接相连的星球数(即度数). 想到先从根到所有点都走一遍,然后贪 ...
- django环境安装与项目创建方式
1.安装django pip install django2.检查django版本 : python -m django --version 3.创建项目 django-admin startproj ...
- .net core迁移实践:项目文件csproj的转换
随着net core的不断更新和生产可用,越来越多的人把现有的应用迁移和部署到net core平台.本文将分享迁移过程中的一个环节,给大家做一下参考. 背景说明 先来介绍一下什么是SDK样式的文件结构 ...
- Disconnected from the target VM, address: '127.0.0.1:1135', transport: 'socket'-SpringBoot启动报错
一.问题由来 本地代码在一次打包后,再次启动项目时报了一个错误,详细的错误信息如下: 2020-10-23 15:10:26.724 [] [main] INFO o.s.c.a.Annotation ...
- 【CF1436B】Prime Square 题解
原题链接 题意简介 要求构造一个由不大于 1e5 的非负数构成的正方形矩阵,矩阵的每个元素不是质数,但每一行.每一列的数字的和都是质数. 思路分析 看到样例二,我们知道数字可以重复. 于是,我们很容易 ...
- linux 卸载 umount 提示device is busy
思路:先杀掉挂载的目录(如:/usr1/)这个进程 fuser -v /usr1/ 再卸载
- java之集合容器(Collection,Map)
首先我们要了解什么是集合? 正所谓容器,比如说杯子是装水的容器,衣柜是装衣服的容器,那么集合就是装数据的容器. 集合有什么特点呢? 1.集合长度是可变的 2.集合用来存储对象 集合和数组有什么区别呢? ...
- 那些鼓吹国内首个.NET 5框架的,该醒醒了!
前两天看过园子里有篇[国内首个 .NET 5 框架 XX 斩获 XXX stars,XXX 发布],一顿羡慕嫉妒恨啊.我这.net core 3.1才上手没几天,还没用热乎呢,你这.NET 5的框架都 ...