Http请求转发服务器实现

Http请求转发服务器实现

需求场景

云服务器通过VPN连接了现场的n台工控机,每台工控机上都在跑web程序,现在我想通过公网直接访问工控机上的web服务,给客户查看现场的具体运行情况,而不是让客户再装一个VPN,简化操作。

现在我们有以下几种方案可以实现:

1.使用代理,将每台工控机的web服务端口代理到云服务器上的一个空闲端口,这种方式的优点是不需要额外写代码实现,只需要通过配置代理即可,缺点是云服务器上端口占用过多,每打开现场的网址url上面都会带一个端口号。

2.使用Http请求转发服务器,将现场和他对应的VPN的ip地址映射起来存到数据库里,前端先请求服务器本地IP地址(127.0.0.1),当通过主界面跳转到某个现场时,通过数据库查询现场VPN的IP地址,然后将之后的请求都转发到对应的VPN地址,即可获取对应现场的数据

具体实现

使用Python实现请求转发服务器
  1. 使用Python实现请求转发服务器非常简单,用flask库即可轻松实现

    python 复制代码
    import queue
    import threading
    
    import requests
    from flask import Flask, request, jsonify
    
    from log import log
    
    # 初始化Flask应用
    app = Flask(__name__, static_folder="dist")
    
    # 捕获所有请求并转发
    @app.route("/", defaults={"path": ""}, methods=["GET", "POST", "PUT", "DELETE"])
    @app.route("/<path:path>", methods=["GET", "POST", "PUT", "DELETE"])
    def catch_all(path):
        # 构建转发的目标 URL,我这里将请求都转发到10.8.0.126服务器上
        forward_url = f"http://10.8.0.126/{path}"
        # 转发请求,并传递请求头、数据以及文件(如果有)
        headers = {key: value for key, value in request.headers if key != "Host"}
        # 获取请求的数据,根据请求方法选择适当的数据处理方式
        data = request.get_json() if request.is_json else request.form or request.data
    
        json_data = data or {}
        try:
            response = requests.request(
                method=request.method,
                url=forward_url,
                headers=headers,
                json=json_data,
                files=request.files,
                params=request.args,
            )
        except requests.RequestException as e:
            return str(e), 500
        # 返回转发请求的响应
        return response.content, response.status_code, response.headers.items()
    
    if __name__ == "__main__":
        app.run(debug=False, host="0.0.0.0", port=9095)
  2. 安装gunicorn库,部署转发服务程序(普通运行只供调试使用,不适用于生产环境)

    bash 复制代码
    pip install gunicorn
  3. 运行转发服务程序

    bash 复制代码
    gunicorn -b 0.0.0.0 -w 4 main:app
使用C++实现请求转发服务器

在用Python完成请求转发服务器的开发后,方案却被领导否决了,因为后台程序都是用C++写的,用Python写不好融合,然后我继续开始研究C++服务端的方案,先采用cpp-httplib库实现。

  1. 代码实现,这里捕获所有请求使用了正则表达式,刚开始因为对这个库和正则不熟悉,卡了较长时间。

    cpp 复制代码
    #include <iostream>
    #include <httplib.h>
    #include <string>
    
    // 定义一个简单的路由处理器
    void catch_all(const httplib::Request& req, httplib::Response& res)
    {
        // 构建转发的目标 URL
        std::string path = req.path;
        std::cout << "path: " << path << std::endl;
        std::cout << "method: " << req.method << std::endl;
        std::string forward_url = "http://10.8.0.126/" + path;
    
        // 转发请求,并传递请求头、数据以及文件(如果有)
        httplib::Headers headers;
        headers = req.headers;
        headers.erase("Host");
    
        // 获取请求的数据,根据请求方法选择适当的数据处理方式
        std::string data;
        data = req.body;
    
        // 使用 httplib 客户端进行转发
        httplib::Client client("10.10.112.139", 9092);
        httplib::Result result;
        if (req.method == "GET") {
            result = client.Get(path, headers);
        } else if (req.method == "POST") {
            result = client.Post(path, headers, data, "application/json");
            std::cout << result->body << std::endl;
        } else if (req.method == "PUT") {
            result = client.Put(path, headers, data, "application/json");
        } else if (req.method == "DELETE") {
            result = client.Delete(path, headers);
        } else {
            res.set_content("Unsupported method", "text/plain");
            res.status = 405;
            return;
        }
    
        if (result && result->status == 200) {
            res.set_content(result->body, result->get_header_value("Content-Type"));
            res.status = result->status;
            for (const auto& header : result->headers) {
                res.headers.emplace(header.first, header.second);
            }
        } else {
            res.set_content("Forward request failed", "text/plain");
            res.status = 500;
        }
    }
    
    int main()
    {
        httplib::Server svr;
    
        // 捕获所有请求并转发
        svr.Get(R"(/.*)", &catch_all);
        svr.Post(R"(/.*)", &catch_all);
    
        auto ret = svr.set_mount_point("/", "/home/narada/ems/www");
    
        svr.listen("0.0.0.0", 8080);
        return 0;
    }
相关推荐
正在走向自律20 分钟前
Linux 服务器部署 DeepSeek 大模型完全指南(2026 版)
linux·运维·服务器·deepseek·部署deepseek·安装ollama·配置api服务
KeyAction66661 小时前
从西班牙高铁追尾看安全系统设计:当违规指令成为输入,防护逻辑如何兜底
运维·服务器·安全
骑着蜗牛撵大象3272 小时前
手写一个 HTTP 服务器:从 socket 到 epoll,Linux 上到底怎么把请求变成响应
linux·服务器·网络·http·epoll·socket编程·并发模型
星恒随风2 小时前
Linux Socket TCP编程(二):逐文件重构多进程、多线程与线程池服务器,深入fork、pthread_create、popen和std::bind
linux·服务器·笔记·学习·tcp/ip
晚风叙码2 小时前
Linux 进程概念(下):程序地址空间与虚拟内存
linux·服务器·算法
无足鸟ICT3 小时前
【RHCA+】影响Linux系统性能的因素
linux·运维·服务器
论文复现现场3 小时前
DeepSeek V4.1 Flash 和 V4 Pro 有什么区别?API 价格、性能与迁移建议
java·服务器·人工智能·python·大模型api·deepseek·deepseek v4.1
沫璃染墨3 小时前
从零入门计算机网络系列(十):HTTP协议进阶——从资源路径解析到状态码与请求头详解
linux·运维·服务器·网络·c++·http
迪康coolmu3 小时前
金融客户数据合规落地:基于迪康端点安全一体化管理系统的四道防线实践
运维·服务器·数据库·经验分享·安全·网络安全·金融
郭小李3 小时前
转发与重定向
java·服务器·数据库