Qt6.9.1起一个图片服务器(支持前端跨域请求,不支持上传,可扩展)

ImageHttpServer.h

cpp 复制代码
#pragma once

#include <QObject>
#include <QHttpServer>
#include <QTcpServer>

class ImageHttpServer : public QObject
{
    Q_OBJECT

public:
    explicit ImageHttpServer(QObject *parent = nullptr);

    bool start(quint16 port);

private:
    void initImagesDir();
    void setupCors();
    void setupRoutes();

    static bool isIllegalPath(const QString &path);

private:
    QHttpServer m_server;
    QTcpServer  m_tcpServer;
};

ImageHttpServer.cpp

cpp 复制代码
#include "ImageHttpServer.h"

#include <QCoreApplication>
#include <QDir>
#include <QFile>
#include <QMimeDatabase>
#include <QDebug>

ImageHttpServer::ImageHttpServer(QObject *parent)
    : QObject(parent)
{
    initImagesDir();
    setupCors();
    setupRoutes();
}

/*
 * 路径安全校验
 */
bool ImageHttpServer::isIllegalPath(const QString &s)
{
    return s.contains("..") || s.contains('/') || s.contains('\\');
}

/*
 * 初始化 images 目录
 */
void ImageHttpServer::initImagesDir()
{
    const QString imagesDir =
        QCoreApplication::applicationDirPath() + "/images";

    QDir dir;
    if (!dir.exists(imagesDir)) {
        qInfo() << "[初始化] images 目录不存在,正在创建...";
        if (dir.mkpath(imagesDir)) {
            qInfo() << "[初始化] images 目录创建成功:" << imagesDir;
        } else {
            qFatal("[初始化] images 目录创建失败!");
        }
    } else {
        qInfo() << "[初始化] images 目录已存在:" << imagesDir;
    }
}

/*
 * 全局 CORS 设置
 */
void ImageHttpServer::setupCors()
{
    m_server.addAfterRequestHandler(
        this,
        [](const QHttpServerRequest &,
           QHttpServerResponse &response) {

            response.headers().append(
                QByteArray("Access-Control-Allow-Origin"),
                QByteArray("*"));

            response.headers().append(
                QByteArray("Access-Control-Allow-Methods"),
                QByteArray("GET, POST, OPTIONS"));

            response.headers().append(
                QByteArray("Access-Control-Allow-Headers"),
                QByteArray("Content-Type"));

            response.headers().append(
                QByteArray("Access-Control-Allow-Credentials"),
                QByteArray("true"));
        });
}

/*
 * 路由配置
 */
void ImageHttpServer::setupRoutes()
{
    // OPTIONS 预检
    m_server.route(".*",
                   QHttpServerRequest::Method::Options,
                   []() {
                       return QHttpServerResponse(
                           QHttpServerResponse::StatusCode::NoContent);
                   });

    // 图片访问
    m_server.route("/image/<arg>/<arg>",
                   [](const QString &folder,
                      const QString &fileName) {

                       qInfo() << "[HTTP] 图片请求"
                               << folder << fileName;

                       if (isIllegalPath(folder) ||
                           isIllegalPath(fileName)) {
                           return QHttpServerResponse(
                               QHttpServerResponse::StatusCode::Forbidden);
                       }

                       const QString baseDir =
                           QCoreApplication::applicationDirPath() + "/images";
                       const QString fullPath =
                           baseDir + "/" + folder + "/" + fileName;

                       QFile file(fullPath);
                       if (!file.exists()) {
                           return QHttpServerResponse(
                               QHttpServerResponse::StatusCode::NotFound);
                       }

                       if (!file.open(QIODevice::ReadOnly)) {
                           return QHttpServerResponse(
                               QHttpServerResponse::StatusCode::InternalServerError);
                       }

                       QMimeDatabase db;
                       const QByteArray data = file.readAll();
                       const QByteArray mime =
                           db.mimeTypeForFile(fullPath).name().toUtf8();

                       return QHttpServerResponse(mime, data);
                   });
}

/*
 * 启动服务器
 */
bool ImageHttpServer::start(quint16 port)
{
    qInfo() << "[TCP] 监听 0.0.0.0:" << port;

    if (!m_tcpServer.listen(QHostAddress::Any, port)) {
        qCritical() << "[TCP] 监听失败:"
                    << m_tcpServer.errorString();
        return false;
    }

    m_server.bind(&m_tcpServer);

    qInfo() << "[HTTP] 服务启动成功";
    qInfo() << "示例:http://127.0.0.1:"
            << port << "/image/cam1/1.jpg";

    return true;
}

main.cpp

cpp 复制代码
#include <QCoreApplication>
#include <QDebug>
#include "ImageHttpServer.h"

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    qInfo() << "===================================";
    qInfo() << "Qt 图片 HTTP 服务器";
    qInfo() << "Qt 版本:" << QT_VERSION_STR;
    qInfo() << "程序目录:" << QCoreApplication::applicationDirPath();
    qInfo() << "===================================";

    ImageHttpServer server;
    if (!server.start(8080)) {
        return -1;
    }

    return app.exec();
}
相关推荐
暮冬-  Gentle°15 分钟前
C++中的命令模式实战
开发语言·c++·算法
Volunteer Technology3 小时前
架构面试题(一)
开发语言·架构·php
清水白石0083 小时前
Python 对象序列化深度解析:pickle、JSON 与自定义协议的取舍之道
开发语言·python·json
dys_Codemonkey3 小时前
如何在树莓派上用 VS Code 优雅直连内部的 Ubuntu 子系统/容器用来访问容器内的文件和代码?
linux·运维·ubuntu·树莓派
2401_876907523 小时前
Python机器学习实践指南
开发语言·python·机器学习
㓗冽3 小时前
分解质因数-进阶题10
c++
图图的点云库3 小时前
高斯滤波实现算法
c++·算法·最小二乘法
努力中的编程者3 小时前
栈和队列(C语言底层实现环形队列)
c语言·开发语言
·醉挽清风·4 小时前
学习笔记—Linux—文件IO
linux·服务器·学习
上海合宙LuatOS4 小时前
LuatOS核心库API——【 string】字符串操作
运维·服务器·物联网·junit·硬件工程·信息与通信·嵌入式实时数据库