Exemplo n.º 1
0
// 上传文件或者数据的实现
void HttpClientPrivate::upload(HttpClientPrivate *d,
                               const QStringList &paths, const QByteArray &data,
                               std::function<void (const QString &)> successHandler,
                               std::function<void (const QString &)> errorHandler,
                               const char *encoding) {
    bool debug = d->debug;
    QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);

    // 创建 Form 表单的参数 Text Part
    QList<QPair<QString, QString> > paramItems = d->params.queryItems();
    for (int i = 0; i < paramItems.size(); ++i) {
        QHttpPart textPart;
        QString name  = paramItems.at(i).first;
        QString value = paramItems.at(i).second;
        textPart.setHeader(QNetworkRequest::ContentDispositionHeader, QString("form-data; name=\"%1\"").arg(name));
        textPart.setBody(value.toUtf8());
        multiPart->append(textPart);
    }

    if (paths.size() > 0) {
        // 上传文件
        QString inputName = paths.size() == 1 ? "file" : "files"; // 一个文件时为 file,多个文件时为 files

        for (const QString &path : paths) {
            if (!path.isEmpty()) {
                // path 不为空时,上传文件
                QFile *file = new QFile(path);
                file->setParent(multiPart); // we cannot delete the file now, so delete it with the multiPart

                // 如果文件打开失败,则释放资源返回
                if(!file->open(QIODevice::ReadOnly)) {
                    QString errorMessage = QString("打开文件失败[%2]: %1").arg(path).arg(file->errorString());

                    if (debug) {
                        qDebug().noquote() << errorMessage;
                    }

                    if (nullptr != errorHandler) {
                        errorHandler(errorMessage);
                    }

                    multiPart->deleteLater();
                    return;
                }

                // 文件上传的参数名为 file,值为文件名
                // 服务器是 Java 的则用 form-data
                // 服务器是 PHP  的则用 multipart/form-data
                QString   disposition = QString("form-data; name=\"%1\"; filename=\"%2\"").arg(inputName).arg(file->fileName());
                QHttpPart filePart;
                filePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant(disposition));
                filePart.setBodyDevice(file);
                multiPart->append(filePart);
            }
        }
    } else {
        // 上传数据
        QString   disposition = QString("form-data; name=\"file\"; filename=\"no-name\"");
        QHttpPart dataPart;
        dataPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant(disposition));
        dataPart.setBody(data);
        multiPart->append(dataPart);
    }

    bool internal;
    QNetworkAccessManager *manager = HttpClientPrivate::getManager(d, &internal);
    QNetworkRequest        request = HttpClientPrivate::createRequest(d, HttpClientPrivate::UPLOAD);
    QNetworkReply           *reply = manager->post(request, multiPart);

    QObject::connect(reply, &QNetworkReply::finished, [=] {
        multiPart->deleteLater(); // 释放资源: multiPart + file

        QString successMessage = HttpClientPrivate::readReply(reply, encoding); // 请求结束时一次性读取所有响应数据
        QString errorMessage   = reply->errorString();
        HttpClientPrivate::handleFinish(debug, successMessage, errorMessage, successHandler, errorHandler,
                                        reply, internal ? manager : nullptr);
    });
}