Russian Qt Forum

Qt => Работа с сетью => Тема начата: Quty от Апрель 06, 2013, 00:43



Название: POST запрос через QNetworkAccessManager
Отправлено: Quty от Апрель 06, 2013, 00:43
Работаю с API Вконтакте, необходимо загрузить фотографию на сервер. Получаю ссылку, она имеет такой вид:
Цитировать
http://cs322519.vk.com/upload.php?act=do_add&mid=96160242&aid=-3&gid=0&hash=c87ebbd3d10060472750b1a1963c946d&rhash=a6e16f727a7d8d11d86a517515506cb6&swfupload=1&api=1&save_big=1&mailphoto=1
Далее необходимо отправить POST запрос на этот адрес, в документации сказано следующее:
Цитировать
Приложение формирует POST-запрос на полученный адрес.
Запрос должен включать поле photo, содержащее файл с изображением (JPG, PNG, BMP или GIF)

В программе реализую это так:
Код:
void MainWindow::uploadScreenshotToServer(QUrl uploadUrl)
{
    QFile file("img.png");
    if(file.open(QIODevice::ReadOnly)) {

        QNetworkRequest request;
        request.setUrl(uploadUrl);
        request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/x-www-form-urlencoded"));
        QByteArray boundary("56gfqgE8VdoO");
        QByteArray data;

        data.append("Content-Type: multipart/form-data; boundary=");
        data.append(boundary);
        data.append("\n\n--");
        data.append(boundary);
        data.append("\n");
        data.append("Content-Disposition: form-data; name=\"photo\"; filename=\"img.png\"\n");
        data.append("Content-Type: image/png\r\n");
        data.append("Content-Transfer-Encoding: binary\n\n");
        data.append(file.readAll());
        data.append("\n--");
        data.append(boundary);
        data.append("--\n");

        reply = manager.post(request, data);
        connect(reply, SIGNAL(finished()), this, SLOT(uploadScreenshotToServerReplyFinished()));
    }
    file.close();
}

В итоге получаю ответ от сервера "{"server":322519,"photo":"[]","hash":"b7f2b773ee8dc8e46d465a4ffb551183"}", т.е. фото вроде как не загрузилось. В документации Qt нашел пример с QHttpMultiPart, решил попробовать так:
Код:
{
    QFile file("img.png");
    if(file.open(QIODevice::ReadOnly)) {
        QNetworkRequest request;
        request.setUrl(uploadUrl);

        QHttpMultiPart multiPart(QHttpMultiPart::FormDataType);
        QHttpPart imagePart;
        imagePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/png"));
        imagePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"photo\""));
        imagePart.setBodyDevice(&file);

        multiPart.append(imagePart);

        reply = manager.post(request, &multiPart);
        connect(reply, SIGNAL(finished()), this, SLOT(uploadScreenshotToServerReplyFinished()));
    }
    file.close();
}

Вообще ничего не получилось - программа "вылетает", дойдя до этого места.
Я неправильно формирую запрос или дело в чем то еще?


Название: Re: POST запрос через QNetworkAccessManager
Отправлено: kataklysm от Апрель 07, 2013, 14:01
Работаю с API Вконтакте, необходимо загрузить фотографию на сервер. Получаю ссылку, она имеет такой вид:
Цитировать
http://cs322519.vk.com/upload.php?act=do_add&mid=96160242&aid=-3&gid=0&hash=c87ebbd3d10060472750b1a1963c946d&rhash=a6e16f727a7d8d11d86a517515506cb6&swfupload=1&api=1&save_big=1&mailphoto=1
Далее необходимо отправить POST запрос на этот адрес, в документации сказано следующее:
Цитировать
Приложение формирует POST-запрос на полученный адрес.
Запрос должен включать поле photo, содержащее файл с изображением (JPG, PNG, BMP или GIF)

В программе реализую это так:
Код:
void MainWindow::uploadScreenshotToServer(QUrl uploadUrl)
{
    QFile file("img.png");
    if(file.open(QIODevice::ReadOnly)) {

        QNetworkRequest request;
        request.setUrl(uploadUrl);
        request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/x-www-form-urlencoded"));
        QByteArray boundary("56gfqgE8VdoO");
        QByteArray data;

        data.append("Content-Type: multipart/form-data; boundary=");
        data.append(boundary);
        data.append("\n\n--");
        data.append(boundary);
        data.append("\n");
        data.append("Content-Disposition: form-data; name=\"photo\"; filename=\"img.png\"\n");
        data.append("Content-Type: image/png\r\n");
        data.append("Content-Transfer-Encoding: binary\n\n");
        data.append(file.readAll());
        data.append("\n--");
        data.append(boundary);
        data.append("--\n");

        reply = manager.post(request, data);
        connect(reply, SIGNAL(finished()), this, SLOT(uploadScreenshotToServerReplyFinished()));
    }
    file.close();
}

В итоге получаю ответ от сервера "{"server":322519,"photo":"[]","hash":"b7f2b773ee8dc8e46d465a4ffb551183"}", т.е. фото вроде как не загрузилось. В документации Qt нашел пример с QHttpMultiPart, решил попробовать так:
Код:
{
    QFile file("img.png");
    if(file.open(QIODevice::ReadOnly)) {
        QNetworkRequest request;
        request.setUrl(uploadUrl);

        QHttpMultiPart multiPart(QHttpMultiPart::FormDataType);
        QHttpPart imagePart;
        imagePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/png"));
        imagePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"photo\""));
        imagePart.setBodyDevice(&file);

        multiPart.append(imagePart);

        reply = manager.post(request, &multiPart);
        connect(reply, SIGNAL(finished()), this, SLOT(uploadScreenshotToServerReplyFinished()));
    }
    file.close();
}

Вообще ничего не получилось - программа "вылетает", дойдя до этого места.
Я неправильно формирую запрос или дело в чем то еще?
Файл(file.close) необходимо закрывать в слоте uploadScreenshotToServerReplyFinished().


Название: Re: POST запрос через QNetworkAccessManager
Отправлено: Quty от Апрель 07, 2013, 14:19
Файл(file.close) необходимо закрывать в слоте uploadScreenshotToServerReplyFinished().
Попробовал, результат тот же, да и по-моему нету разницы, ведь данные из файла к моменту отправки запроса на сервер уже прочитаны полностью.


Название: Re: POST запрос через QNetworkAccessManager
Отправлено: Quty от Апрель 08, 2013, 11:39
Разобрался. Может кому пригодится:
Код:
void MainWindow::uploadScreenshotToServer(QUrl uploadUrl)
{
    QBuffer buffer(&data);
    buffer.open(QIODevice::ReadWrite);
    screenshotPixmap.save(&buffer, "png");
    buffer.close();

    QNetworkRequest request;
    request.setUrl(uploadUrl);

    QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
    QHttpPart imagePart;
    imagePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/png"));
    if(saveMethod->currentIndex() == 0) {
        imagePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"photo\"; filename=\"img.png\""));
    }
    else if(saveMethod->currentIndex() == 1) {
        imagePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"file1\"; filename=\"img.png\""));
    }
    imagePart.setBody(data);
    multiPart->append(imagePart);

    reply = manager.post(request, multiPart);
    connect(reply, SIGNAL(finished()), this, SLOT(uploadScreenshotToServerReplyFinished()));
    connect(reply, SIGNAL(finished()), multiPart, SLOT(deleteLater()));
}

Ошибка была тут:
Код:
imagePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"photo\"; filename=\"img.png\""));
Добавил filename=\"img.png\" в заголовок и все заработало как надо.