You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C++的uWebSockets HTTP服务器中托管静态文件?

在uWebSockets C++ HTTP服务器中实现静态文件托管

uWebSockets本身没有内置静态文件托管功能,需要手动实现类似express.static的逻辑,核心是通过通配路由匹配静态资源请求,将请求路径映射到public目录,并处理文件读取、响应头设置和错误情况。

实现步骤与代码示例

1. 编写静态文件处理函数

这个函数会完成路径映射、文件校验、Content-Type设置和响应返回:

#include <uWebSockets/App.h>
#include <rapidjson/rapidjson.h>
#include "util/AsyncFileReader.h"
#include "util/AsyncFileStreamer.h"
#include <iostream>
#include <string>
#include <unordered_map>
#include <filesystem> // C++17及以上可用,用于文件存在性检查和路径安全处理

namespace fs = std::filesystem;

// 常见文件后缀与Content-Type映射
const std::unordered_map<std::string, std::string> MIME_TYPES = {
    {".html", "text/html; charset=utf-8"},
    {".css", "text/css"},
    {".js", "application/javascript"},
    {".json", "application/json"},
    {".png", "image/png"},
    {".jpg", "image/jpeg"},
    {".gif", "image/gif"},
    {".svg", "image/svg+xml"},
    {".ico", "image/x-icon"}
};

void handleStaticFiles(uWS::HttpResponse<false> *res, uWS::HttpRequest *req) {
    // 1. 构建文件路径:将请求路径映射到public目录
    std::string filePath = "./public" + std::string(req->getUrl());

    // 2. 路径安全检查:防止路径遍历攻击(比如请求/../etc/passwd)
    fs::path publicPath = fs::absolute("./public");
    fs::path targetPath = fs::absolute(filePath);
    if (!fs::exists(targetPath) || !fs::is_regular_file(targetPath) || 
        targetPath.string().find(publicPath.string()) != 0) {
        // 文件不存在、不是普通文件或路径越界,返回404
        res->writeStatus(uWS::HTTP_404_NOT_FOUND);
        res->writeHeader("Content-Type", "text/plain");
        res->end("404 Not Found");
        return;
    }

    // 3. 根据文件后缀设置Content-Type
    std::string ext = targetPath.extension().string();
    auto it = MIME_TYPES.find(ext);
    std::string contentType = (it != MIME_TYPES.end()) ? it->second : "application/octet-stream";
    res->writeHeader("Content-Type", contentType.c_str());

    // 4. 异步读取文件并返回响应(使用你已有的AsyncFileReader)
    AsyncFileReader fileReader(filePath);
    res->end(fileReader.peek(0));
}

void get_home(uWS::HttpResponse<false> *res, uWS::HttpRequest *req) {
    res->writeHeader("Content-Type", "text/html; charset=utf8");
    AsyncFileReader page_contents("./public/home.html");
    res->end(page_contents.peek(0));
}

int main() {
    int port{8087};

    uWS::App app = uWS::App();
    // 先注册具体路由,再注册静态文件通配路由(确保优先匹配具体路径)
    app.get("/", get_home);
    // 匹配所有GET请求,处理静态资源
    app.get("/*", handleStaticFiles);

    app.listen(port, [&port](auto *token) {
        if (token) {
            std::cout << "Listening on port " << port << std::endl;
        }
    }).run();

    return 0;
}

关键细节说明

  • 路由顺序:先注册具体路由(如/),再注册通配路由/*,这样uWS会优先匹配具体路径,避免静态文件路由拦截首页请求。
  • 路径安全:使用std::filesystem做绝对路径校验,确保请求的文件始终在public目录内,防止路径遍历攻击。
  • Content-Type处理:通过后缀映射表设置正确的响应头,避免浏览器无法识别文件类型。
  • 错误处理:当文件不存在或路径非法时,返回404状态码和提示信息。

大文件优化建议

如果需要处理视频、大图片这类大文件,建议使用AsyncFileStreamer替代AsyncFileReader,实现流式响应避免一次性加载大文件到内存:

// 替换handleStaticFiles中的文件读取部分
AsyncFileStreamer fileStreamer(filePath);
fileStreamer.stream(res);

内容的提问来源于stack exchange,提问作者Fillyjonk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 05:20:27