在我们的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实现超轻量级网关(反向代理、转发)的更多相关文章

  1. 【应用服务 App Service】 App Service Rewrite 实例 - 反向代理转发功能

    问题描述 在使用Azure App Service(应用服务)时,有时候需要在不同的站点之间进行跳转,但是希望通过通过访问同一个域名的方式来实现反向代理.如果创建应用时候选择的是Window服务,这时 ...

  2. SpringCloud微服务笔记-Nginx实现网关反向代理

    背景 当前在SpringCloud微服务架构下,网关作为服务的入口尤为重要,一旦网关发生单点故障会导致整个服务集群瘫痪,为了保证网关的高可用可以通过Nginx的反向代理功能实现网关的高可用. 项目源码 ...

  3. nginx反向代理转发后页面上的js css文件无法加载【原创】

    故障现象:nginx做代理转发后,发现页面上的js css文件无法加载,页面样式乱了. 原因:没有配置静态资源 解决js css文件无法加载无法访问的问题 解决办法: 修改配置文件nginx.conf ...

  4. IIS充当反向代理转发请求到Kestrel

    接着上篇博文为ASP.NetCore程序启用SSL的code,这篇将介绍如何用IIS充当反向代理的角色转发请求到Kestrel服务器 介绍 与ASP.NET不同,ASP.netCore使用的是自托管w ...

  5. Nginx反向代理转发Host设置

    默认情况下反向代理是不会转发请求中的Host头部,如果需要转发,则需要配置红色字体表示的选项参数. location /t02 { proxy_set_header Host $host; proxy ...

  6. nginx证书制作以及配置https并设置访问http自动跳转https(反向代理转发jboss)

    nginx证书制作以及配置https并设置访问http自动跳转https 默认情况下ssl模块并未被安装,如果要使用该模块则需要在编译时指定–with-http_ssl_module参数,安装模块依赖 ...

  7. 【转】Nginx反向代理转发tomcat

    http://blog.csdn.net/mlc1218559742/article/details/53117520 最近刚接触nginx,在网上查阅了相关资料,看到最多的形容nginx的词就是反向 ...

  8. 【Nginx】Nginx反向代理转发Host设置

    #事故现场: 服务器A(Nginx服务器):192.168.2.126 服务器B(Web服务器):192.168.2.221 服务器A反向代理服务器B,A配置了upstream为: http { up ...

  9. Spring Boot @Trasactionl 失效, JDK,CGLIB动态代理

    来自: https://www.cnblogs.com/sweetchildomine/p/6978037.html?utm_source=itdadao&utm_medium=referra ...

随机推荐

  1. 【故障公告】博客系统升级到 .NET 5.0 引发的故障

    昨天晚上我们将博客系统从 .NET Core 3.1 升级到了 .NET 5.0 ,本来是一次很有信心的升级,但没有想到在今天下午访问高峰时竟然出现了故障,大量请求访问速度变慢或者因为下面的数据库连接 ...

  2. PHP之Trait详解 转

    php从以前到现在一直都是单继承的语言,无法同时从两个基类中继承属性和方法,为了解决这个问题,php出了Trait这个特性 用法:通过在类中使用use 关键字,声明要组合的Trait名称,具体的Tra ...

  3. composer 打印美化

    { "name": "brady_frmwork", "description":"php framwork", &qu ...

  4. zookeeper的管理功能

    一,查看当前zookeeper的版本 [liuhongdi@localhost ~]$ echo stat|nc 127.0.0.1 2181 Zookeeper version: 3.5.6-c11 ...

  5. ImageMagick实现图片加水印(ImageMagick6.9.10)

    一,ImageMagick的安装 请参见: https://www.cnblogs.com/architectforest/p/12807514.html 说明:刘宏缔的架构森林是一个专注架构的博客, ...

  6. scrapy基本爬虫,采集多页

    # -*- coding: utf-8 -*- import csv import scrapy class GjSpider(scrapy.Spider): name = 'gj' allowed_ ...

  7. Java基础之类型转换总结篇

    Java中,经常可以遇到类型转换的场景,从变量的定义到复制.数值变量的计算到方法的参数传递.基类与派生类间的造型等,随处可见类型转换的身影.Java中的类型转换在Java编码中具有重要的作用.    ...

  8. 数据结构(C++)——顺序栈

    顺序栈结构 #include<iostream> #define MaxSize 50 using namespace std; typedef int ElemType; typedef ...

  9. 第 1 篇:Vue.js 很高兴认识你

    作者:HelloGitHub--追梦人物 Hello Vue 既然是学习编程,那就遵循一下那个古老的传统仪式. 首先我们新建一个 todos.html 文件,用任何一个你喜欢的文本编辑器或者 IDE ...

  10. 从小白到 6 个 offer,我究竟是怎么刷题的?

    最近自习室里又兴起了一阵刷题潮,大家相约刷题~ 今天和大家系统分享下我去年转行时的一个刷题过程和方法,希望对你有所帮助. 首先介绍下我的编程基础,我学的是金融工程专业,硕士时学过 C++ 的课,这也是 ...