QHttpMultiPart生成不同的边界

时间:2016-09-17 16:38:10

标签: spring qt http http-headers mime

当我尝试按QHttpMultiPart上传文件时,出现问题。我使用CommonsMultipartResolver.isMultipart()验证请求,并返回false

所以我通过Wireshark捕获帧,我发现了一个有趣的事情:帧中的边界都是不同的。

Wireshark screenshot

这是我的客户代码

    QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);

    QHttpPart zipPart;
    zipPart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/zip"));
    zipPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"file\""));
    QFile *file = new QFile(pakPath);
    file->open(QIODevice::ReadOnly);
    zipPart.setBodyDevice(file);

    multiPart->append(zipPart);

    QNetworkRequest *request = new QNetworkRequest(QUrl(url));

    manager->put(*request, multiPart);

服务器代码

    CommonsMultipartResolver(request.getSession().getServletContext()); 
    if( multipartResolver.isMultipart(request) ) {    // here return false
        ...

我有两个问题:

Q1:CommonsMultipartResolver中的不同边界是否异常?

Q2:不同边界是正常还是Qt出错?

1 个答案:

答案 0 :(得分:0)

我也有同样的问题,我的边界应该是“”, 我找到了有关QHttpMultiPart类的源代码,我发现qt手动设置了“”。因此,无论我们设置什么,都将始终带有“”。 qt QHttpMultiPart source code

<pre><code>QNetworkRequest QNetworkAccessManagerPrivate::prepareMultipart(const QNetworkRequest &request, QHttpMultiPart *multiPart)
{
    // copy the request, we probably need to add some headers
    QNetworkRequest newRequest(request);
    // add Content-Type header if not there already
    if (!request.header(QNetworkRequest::ContentTypeHeader).isValid()) {
        QByteArray contentType;
        contentType.reserve(34 + multiPart->d_func()->boundary.count());
        contentType += "multipart/";
        switch (multiPart->d_func()->contentType) {
        case QHttpMultiPart::RelatedType:
            contentType += "related";
            break;
        case QHttpMultiPart::FormDataType:
            contentType += "form-data";
            break;
        case QHttpMultiPart::AlternativeType:
            contentType += "alternative";
            break;
        default:
            contentType += "mixed";
            break;
        }
        // putting the boundary into quotes, recommended in RFC 2046 section 5.1.1
        contentType += "; boundary=\"" + multiPart->d_func()->boundary + '"';
        newRequest.setHeader(QNetworkRequest::ContentTypeHeader, QVariant(contentType));
    }
    // add MIME-Version header if not there already (we must include the header
    // if the message conforms to RFC 2045, see section 4 of that RFC)
    QByteArray mimeHeader("MIME-Version");
    if (!request.hasRawHeader(mimeHeader))
        newRequest.setRawHeader(mimeHeader, QByteArray("1.0"));
    QIODevice *device = multiPart->d_func()->device;
    if (!device->isReadable()) {
        if (!device->isOpen()) {
            if (!device->open(QIODevice::ReadOnly))
                qWarning("could not open device for reading");
        } else {
            qWarning("device is not readable");
        }
    }
    return newRequest;
}
</code></pre>

我试图继承QHttpMultiPart并重写QNetworkAccessManagerPrivate :: prepareMultipart(const QNetworkRequest&request,QHttpMultiPart * multiPart)函数,但这似乎太麻烦了。

最后,我找到了一种简单的方法来解决该问题,它只需要重置边界参数agian,即在发布数据之前。有效。这是我的代码

<pre><code>
void PeddingBizUI::ossUploadPicture_post(PolicyInfo policy, QString pathName)
{


    QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);

    QHttpPart keyPart;
    QString fileName = getFileNameFromPath(pathName);
    keyPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form- 
    data; name=\"key\""));
    QByteArray ba = QByteArray(QString(policy.dir + 
    fileName).toStdString().data());
    qDebug()<<ba;
    keyPart.setBody(ba);

    QHttpPart policyPart;
    policyPart.setHeader(QNetworkRequest::ContentDispositionHeader, 
    QVariant("form-data; name=\"policy\""));
    policyPart.setBody(policy.policy.toStdString().data());

    QHttpPart SignaturePart;
    SignaturePart.setHeader(QNetworkRequest::ContentDispositionHeader, 
    QVariant("form-data; name=\"Signature\""));
    SignaturePart.setBody(policy.signature.toStdString().data());

    QHttpPart OSSAccessKeyIdPart;
    OSSAccessKeyIdPart.setHeader(QNetworkRequest::ContentDispositionHeader, 
    QVariant("form-data; name=\"OSSAccessKeyId\""));
    OSSAccessKeyIdPart.setBody(policy.accessId.toStdString().data());

    QHttpPart success_action_statusPart;
    success_action_statusPart.setHeader(QNetworkRequest::ContentDispositionHeader, 
    QVariant("form-data; name=\"success_action_status\""));
    success_action_statusPart.setBody(QByteArray::number(200));

    QHttpPart aclPart;
    aclPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form- 
    data; name=\"x-oss-object-acl\""));
    aclPart.setBody("public-read");

    QHttpPart imagePart;

    QString str = QString("form-data; name=\"file\"; 
    filename=\"%1\"").arg(fileName);
    qDebug()<<fileName;
    imagePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant(str));              
    //不可调换header的先后顺序否则导致
    imagePart.setHeader(QNetworkRequest::ContentTypeHeader, 
   QVariant("image/jpeg"));            //请求失败, 提示body data not well formed 失 
   败
    QFile *fileOpen = new QFile(pathName);
    fileOpen->open(QIODevice::ReadOnly);
    imagePart.setBodyDevice(fileOpen);
    fileOpen->setParent(multiPart); // we cannot delete the file now, so delete it 
    with the multiPart


    multiPart->append(keyPart);
    multiPart->append(policyPart);
    multiPart->append(SignaturePart);
    multiPart->append(OSSAccessKeyIdPart);
    multiPart->append(success_action_statusPart);
    //multiPart->append(aclPart);
    multiPart->append(imagePart);

    quint32 random[6];
    QRandomGenerator::global()->fillRange(random);
    QByteArray boundary = "--boundary_zyl_"
               + QByteArray::fromRawData(reinterpret_cast<char *>(random), 
    sizeof(random)).toBase64();

    QUrl url(policy.host);
    //    QUrl url("http://arithmetic-oss.oss-cn-shenzhen.aliyuncs.com");
    QNetworkRequest request(url);
    QByteArray contentType;
    contentType += "multipart/";
    contentType += "form-data";
    contentType += "; boundary=";
    contentType += boundary;
    multiPart->setBoundary(boundary);
    request.setHeader(QNetworkRequest::ContentTypeHeader, contentType);

    QNetworkReply *reply = m_netUtils.m_manager->post(request, multiPart);
    connect(reply, &QNetworkReply::finished, this, [this, multiPart](){
        QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
        qDebug()<<"ossUploadPicture_post response";
        onOssUploadPictureResponse(reply);
        multiPart->setParent(reply);        //内存泄露
        reply->deleteLater();
    });
    // delete the multiPart with the reply
}</code></pre>

然后解决问题。