Http请求转发服务器实现

打印 上一主题 下一主题

主题 1000|帖子 1000|积分 3000

Http请求转发服务器实现

需求场景

云服务器通过VPN连接了现场的n台工控机,每台工控机上都在跑web程序,如今我想通过公网直接访问工控机上的web服务,给客户检察现场的具体运行情况,而不是让客户再装一个VPN,简化操作。
如今我们有以下几种方案可以实现:
1.使用代理,将每台工控机的web服务端口代理到云服务器上的一个空闲端口,这种方式的优点是不需要额外写代码实现,只需要通过配置代理即可,缺点是云服务器上端口占用过多,每打开现场的网址url上面都会带一个端标语。
2.使用Http请求转发服务器,将现场和他对应的VPN的ip地址映射起来存到数据库里,前端先请求服务器当地IP地址(127.0.0.1),当通过主界面跳转到某个现场时,通过数据库查询现场VPN的IP地址,然后将之后的请求都转发到对应的VPN地址,即可获取对应现场的数据
具体实现

使用Python实现请求转发服务器


  • 使用Python实现请求转发服务器非常简单,用flask库即可轻松实现
    1. import queue
    2. import threading
    3. import requests
    4. from flask import Flask, request, jsonify
    5. from log import log
    6. # 初始化Flask应用
    7. app = Flask(__name__, static_folder="dist")
    8. # 捕获所有请求并转发
    9. @app.route("/", defaults={"path": ""}, methods=["GET", "POST", "PUT", "DELETE"])
    10. @app.route("/<path:path>", methods=["GET", "POST", "PUT", "DELETE"])
    11. def catch_all(path):
    12.     # 构建转发的目标 URL,我这里将请求都转发到10.8.0.126服务器上
    13.     forward_url = f"http://10.8.0.126/{path}"
    14.     # 转发请求,并传递请求头、数据以及文件(如果有)
    15.     headers = {key: value for key, value in request.headers if key != "Host"}
    16.     # 获取请求的数据,根据请求方法选择适当的数据处理方式
    17.     data = request.get_json() if request.is_json else request.form or request.data
    18.     json_data = data or {}
    19.     try:
    20.         response = requests.request(
    21.             method=request.method,
    22.             url=forward_url,
    23.             headers=headers,
    24.             json=json_data,
    25.             files=request.files,
    26.             params=request.args,
    27.         )
    28.     except requests.RequestException as e:
    29.         return str(e), 500
    30.     # 返回转发请求的响应
    31.     return response.content, response.status_code, response.headers.items()
    32. if __name__ == "__main__":
    33.     app.run(debug=False, host="0.0.0.0", port=9095)
    复制代码
  • 安装gunicorn库,部署转发服务程序(普通运行只供调试使用,不实用于生产情况)
    1. pip install gunicorn
    复制代码
  • 运行转发服务程序
    1. gunicorn -b 0.0.0.0 -w 4 main:app
    复制代码

使用C++实现请求转发服务器

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

  • 代码实现,这里捕捉所有请求使用了正则表达式,刚开始因为对这个库和正则不熟悉,卡了较长时间。
    1. #include <iostream>
    2. #include <httplib.h>
    3. #include <string>
    4. // 定义一个简单的路由处理器
    5. void catch_all(const httplib::Request& req, httplib::Response& res)
    6. {
    7.     // 构建转发的目标 URL
    8.     std::string path = req.path;
    9.     std::cout << "path: " << path << std::endl;
    10.     std::cout << "method: " << req.method << std::endl;
    11.     std::string forward_url = "http://10.8.0.126/" + path;
    12.     // 转发请求,并传递请求头、数据以及文件(如果有)
    13.     httplib::Headers headers;
    14.     headers = req.headers;
    15.     headers.erase("Host");
    16.     // 获取请求的数据,根据请求方法选择适当的数据处理方式
    17.     std::string data;
    18.     data = req.body;
    19.     // 使用 httplib 客户端进行转发
    20.     httplib::Client client("10.10.112.139", 9092);
    21.     httplib::Result result;
    22.     if (req.method == "GET") {
    23.         result = client.Get(path, headers);
    24.     } else if (req.method == "POST") {
    25.         result = client.Post(path, headers, data, "application/json");
    26.         std::cout << result->body << std::endl;
    27.     } else if (req.method == "PUT") {
    28.         result = client.Put(path, headers, data, "application/json");
    29.     } else if (req.method == "DELETE") {
    30.         result = client.Delete(path, headers);
    31.     } else {
    32.         res.set_content("Unsupported method", "text/plain");
    33.         res.status = 405;
    34.         return;
    35.     }
    36.     if (result && result->status == 200) {
    37.         res.set_content(result->body, result->get_header_value("Content-Type"));
    38.         res.status = result->status;
    39.         for (const auto& header : result->headers) {
    40.             res.headers.emplace(header.first, header.second);
    41.         }
    42.     } else {
    43.         res.set_content("Forward request failed", "text/plain");
    44.         res.status = 500;
    45.     }
    46. }
    47. int main()
    48. {
    49.     httplib::Server svr;
    50.     // 捕获所有请求并转发
    51.     svr.Get(R"(/.*)", &catch_all);
    52.     svr.Post(R"(/.*)", &catch_all);
    53.     auto ret = svr.set_mount_point("/", "/home/narada/ems/www");
    54.     svr.listen("0.0.0.0", 8080);
    55.     return 0;
    56. }
    复制代码

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

王海鱼

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表