【问题标题】:Upload files using QNetworkManager is not woking使用 NetworkManager 上传文件不起作用
【发布时间】:2021-05-15 23:16:10
【问题描述】:

所以我正在尝试使用 Qt Network Manager 将一个简单的文本文件上传到我正在服务的 php 脚本中。但它不起作用。我尝试了使用 QHttpMultiPart 和在请求中设置原始数据标头的示例,但没有任何效果。

这是我的 Qt 代码:

#include <QCoreApplication>

#include <QNetworkReply>
#include <QNetworkRequest>
#include <QDebug>
#include <QEventLoop>
#include <QObject>
#include <QVariantMap>
#include <QJsonDocument>
#include <QFile>
#include <QHttpMultiPart>

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

    QString address = "http://localhost/api_test/";
    //address = "https://dashboard.viewmind.ai/dashboard/api_test/welcome.php";

    QUrl api_url = QUrl(address);

    QVariantMap postDatamap;
    postDatamap.insert("Name","Ariel Ñoño");
    postDatamap.insert("Age",37);

    QJsonDocument json = QJsonDocument::fromVariant(postDatamap);

    qDebug() << "Sending the request";
    QNetworkAccessManager *networkManager = new QNetworkAccessManager();
    QNetworkRequest request(api_url);


    QString bound = "<<<<<boundary>>>>>";
    request.setRawHeader(QString("Content-Type").toUtf8(),QString("multipart/form-postData; boundary=" + bound).toUtf8());


    //QByteArray postData;
    QByteArray postData(QString("--" + bound + "\r\n").toUtf8());
    postData.append("Content-Disposition: form-postData; name=\"action\"\r\n\r\n");
    postData.append("welcome.php\r\n");
    postData.append(QString("--" + bound + "\r\n").toUtf8());
    postData.append("Content-Disposition: form-postData; name=\"uploaded\"; filename=\"");
    postData.append("test.json");
    postData.append("\"\r\n");
    postData.append("Content-Type: text/xml\r\n\r\n"); //postData type

    QFile file("test.json");
        if (!file.open(QIODevice::ReadOnly)){
            qDebug() << "QFile Error: File not found!";
            delete networkManager;
            return 0;
        } else { qDebug() << "File found, proceed as planned"; }

    postData.append(file.readAll());
    postData.append("\r\n");
    postData.append(QString("--" + bound + "\r\n").toUtf8());

    request.setRawHeader(QString("Content-Length").toUtf8(), QString::number(postData.length()).toUtf8());


    //request.setHeader(QNetworkRequest::ContentTypeHeader,"application/json; charset=utf-8");
    //request.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-postData; name=\"text\""));
    //qDebug() << QString(json.toJson());

    //QHttpMultiPart multipart(QHttpMultiPart::FormDataType);
    //QHttpPart textPart;

//    QFile file("test.json");
//    if (!file.open(QIODevice::ReadOnly)){
//        qDebug() << "Could not open file for reading";
//        delete networkManager;
//        return 0;
//    }
    //textPart.setBodyDevice(&file);
    //multipart.append(textPart);
    //file.setParent(&multipart);

    //QNetworkReply *reply = networkManager->post(request,json.toJson());
    //QNetworkReply *reply = networkManager->post(request,file.readAll());
    //QNetworkReply *reply = networkManager->post(request,&multipart);
    QNetworkReply *reply = networkManager->post(request,postData);
    //file.setParent(reply);
    //multipart.setParent(reply);

    // Using the loop to wait for the reply to finish.
    QEventLoop loop;
    QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
    loop.exec();

    qDebug() << "Reply is finished";

    //file.close();

    if (reply->error() != QNetworkReply::NoError){
        qDebug() << "The following error ocurred";
        qDebug() << reply->errorString();
        return 0;
    }

    QString postData_returned = QString::fromUtf8(reply->readAll());

    qDebug() << "DATA RETURNED";
    qDebug() << postData_returned;

    return 0;
}

我的 php 代码是这样的

<?php
header("Access-Control-Allow-Origin: *");  // Anyone can access
header("Content-Type: application/json; charset=UTF-8"); // Will return json data. 

error_log("FILES iS");
vardump_toerror($_FILES);

?>

我的理解是 $_FILES 超级全局应该填充文件信息。我弄错了吗?但是打印出来的显示是空的。

【问题讨论】:

    标签: php qt


    【解决方案1】:

    我不是 PHP 专家,但我发现没有必要使用内容类型 application/json,因为 multipart(提交表单)不是该协议的一部分。另一方面,我找不到vardump_toerror 函数的引用,所以我用var_dump 更改所以我的测试php 是:

    <?php
      var_dump($_FILES);
    ?>
    

    在 PyQt5 的 previous question 中,我为 django 实现了类似的逻辑,该逻辑也适用于这种情况,因此我将显示翻译。

    #include <QCoreApplication>
    #include <QFile>
    #include <QHttpMultiPart>
    #include <QNetworkAccessManager>
    #include <QNetworkReply>
    #include <QTextCodec>
    
    QHttpMultiPart *buildMultpart(const QVariantMap & data, const QMap<QString, QString> filenames){
    
        QHttpMultiPart *multipart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
        QVariantMap::const_iterator i_data = data.constBegin();
        while (i_data != data.constEnd()) {
            QHttpPart postpart;
            postpart.setHeader(QNetworkRequest::ContentDispositionHeader, QString("form-data; name=\"%1\"").arg(i_data.key()));
            postpart.setBody(i_data.value().toByteArray());
            multipart->append(postpart);
            ++i_data;
        }
        QMap<QString, QString>::const_iterator i_filenames = filenames.constBegin();
        while (i_filenames != filenames.constEnd()) {
    
            QFile *file = new QFile(i_filenames.value());
            if(!file->open(QIODevice::ReadOnly)){
                delete  file;
                continue;
            }
            QHttpPart postpart;
            postpart.setHeader(QNetworkRequest::ContentDispositionHeader,
                               QString("form-data; name=\"%1\"; filename=\"%2\"")
                               .arg(i_filenames.key(), file->fileName()));
            postpart.setBodyDevice(file);
            multipart->append(postpart);
            file->setParent(multipart);
            ++i_filenames;
        }
        return multipart;
    }
    
    
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
        QUrl url("http://localhost:4000/upload.php");
        QNetworkAccessManager manager;
        QMap<QString, QString> filenames;
        filenames["fileToUpload"] = "/path/of/data.txt";
        QHttpMultiPart *multipart = buildMultpart({}, filenames);
        QNetworkRequest request(url);
        QNetworkReply *reply = manager.post(request, multipart);
        multipart->setParent(reply);
        QObject::connect(reply, &QNetworkReply::finished, QCoreApplication::quit);
        a.exec();
        if(reply->error() == QNetworkReply::NoError){
            qDebug() << reply->readAll();
        }
        else{
            qDebug() << reply->error() << reply->errorString();
        }
        delete reply;
    
        return 0;
    }
    

    输出:

    "array(1) {\n  [\"fileToUpload\"]=>\n  array(5) {\n    [\"name\"]=>\n    string(8) \"data.txt\"\n    [\"type\"]=>\n    string(0) \"\"\n    [\"tmp_name\"]=>\n    string(14) \"/tmp/phpVmOAhO\"\n    [\"error\"]=>\n    int(0)\n    [\"size\"]=>\n    int(6)\n  }\n}\n"
    

    【讨论】:

    • 你是男人!!!像魅力一样工作。抱歉 vardump_toerror。它只是一个将变量转储到字符串并将变量转储到错误日志的函数。我使用了您的代码原样并且它有效。我要弄清楚我和我的区别是什么。谢谢!!!
    猜你喜欢
    • 2016-12-20
    • 1970-01-01
    • 1970-01-01
    • 2010-12-27
    • 2014-05-15
    • 2018-05-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多