qicosmos / cinatra

modern c++(c++20), cross-platform, header-only, easy to use http framework
MIT License
1.81k stars 369 forks source link

上传二进制文件无法使用 #592

Closed tonychen0924 closed 1 month ago

tonychen0924 commented 1 month ago

上传二进制文件无法使用,虽然文件正常传输到服务器端了,但通过md5sum对比发现二进制文件不一致,并且也无法运行。相关的资料并没有找到很多,参考的":cinatra/example/main.cpp"中的"/form_data"部分

服务端的代码如下:

include

include

include

include

void save_file(const std::string& file_content, const std::string& file_name) { std::ofstream ofs(file_name, std::ios::binary); ofs.write(file_content.c_str(), file_content.size()); ofs.close(); }

int main(int argc, char **argv) { cinatra::coro_http_server server(std::thread::hardware_concurrency(), 8090, "127.0.0.1", true);

server.set_http_handler<cinatra::GET, cinatra::POST>(
    "/upload", [](cinatra::coro_http_request& req, cinatra::coro_http_response& resp) -> async_simple::coro::Lazy<void>
    {
        assert(req.get_content_type() == cinatra::content_type::multipart);
        auto boundary = req.get_boundary();
        cinatra::multipart_reader_t multipart(req.get_conn());
        std::string file_name;
        std::string file_content;

        while (true) {
            auto part_head = co_await multipart.read_part_head(boundary);
            if (part_head.ec) {
                resp.set_status_and_content(cinatra::status_type::bad_request, "bad_request");
                co_return;
            }

            if (!part_head.filename.empty()) {
                std::cout << "Filename: " << part_head.filename << "\n";
                file_name = part_head.filename;
            }

            auto part_body = co_await multipart.read_part_body(boundary);
            if (part_body.ec) {
                resp.set_status_and_content(cinatra::status_type::bad_request, "bad_request");
                co_return;
            }

            file_content.append(part_body.data);

            if (part_body.eof) {
                break;
            }
        }

        if (file_name.empty() || file_content.empty()) {
            resp.set_status_and_content(cinatra::status_type::bad_request, "Missing file content or file name");
        } else {
            save_file(file_content, file_name);
            resp.set_status_and_content(cinatra::status_type::ok, "File uploaded successfully");
        }
    });

server.sync_start();

return 0;

}

客户端的代码如下:

include "MasterClient.hpp"

std::string read_file(const std::string& file_path) { std::ifstream file(file_path, std::ios::binary); if (!file) { throw std::runtime_error("Failed to open file"); } std::ostringstream ss; ss << file.rdbuf(); return ss.str(); }

int main(int argc, char** argv) { // 访问服务器的url std::string uri; cinatra::coro_http_client client{};

// 使用 std::filesystem::current_path() 获取当前工作目录
std::filesystem::path current_path = std::filesystem::current_path();
// 将路径转换为字符串并输出
std::cout << "Current working directory: " << current_path.string() << std::endl;
// std::string file_path = current_path.string() + "/../../dioDev.ko";
std::string file_path = current_path.string() + "/../../IteratorAuto.exe";
std::cout << "file_path:" << file_path << std::endl;
// std::string file_name = "dioDev.ko";    // 服务器上保存的文件名
std::string file_name = "IteratorAuto.exe";    // 服务器上保存的文件名
std::string file_content = read_file(file_path);

// cpr::Multipart 对象支持发送多部分表单数据,适用于文件上传等场景
cpr::Multipart multipart{
    {"file_name", file_name},
    {"file_content", cpr::File{file_path}}
};

// 使用 cpr 库发送 POST 请求
cpr::Response res = cpr::Post
(
    cpr::Url{"http://127.0.0.1:8090/upload"},
    // cpr::Payload
    // {
    //     {"file_name", file_name},
    //     {"file_content", file_content}
    // }
    multipart
);

if (res.error)
{
    std::cout << "Network error: " << res.error.message << "\n";
}
else
{
    std::cout << "Status: " << res.status_code << "\n";
    std::cout << "Body: " << res.text << "\n";
}

}

tonychen0924 commented 1 month ago
cpr::Multipart multipart
{
    {
        cpr::Part(
            file_name,
            cpr::File(file_path)
        )
    }
};

在服务端的head获取的就是file_name,内容则是cpr::File(file_path) 并不需要2个key和value

helintongh commented 1 month ago

thanks