© EVILEG 2015-2018
Рекомендует хостинг
TIMEWEB
16 августа 2018 г. 16:48

HTTP QNetworkAccessManager

C++, Qt, QNetworkAccessManager, http




Пытаюсь создать post() запрос -залогиниться на сервере и получить cookie. Велосипед изобретать не стал - все сделалкак по книге:  

 QNetworkAccessManager *manager;

    manager = new QNetworkAccessManager ();

    QNetworkRequest req;

    req.setUrl(QUrl("http://********.by/login"));
    req.setHeader(QNetworkRequest::ContentTypeHeader,"application/x-www-form-urlencoded");


    //get-запрос идет нормально
    //manager->get(QNetworkRequest(QUrl("http://env-2764881.mycloud.by/login")));

    QByteArray postData;
    postData.append("email=*******@gmail.com&");
    postData.append("password=******");
    //Создаем QCookieJar:
    manager->setCookieJar(new QNetworkCookieJar(manager));

    connect (manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(replyFinished(QNetworkReply *)));
  manager->post(req, postData);  
СЛОТ


void Downloader::replyFinished(QNetworkReply *reply)
{
    qDebug()<<"answer";

    if(reply->error())
    {
          qDebug()<<"ERROR";
          qDebug()<<reply->errorString();
    }
    else
    {
           qDebug()<<"reply->readAll()\n"<<reply->readAll();       
    }
    reply->deleteLater();
}

Как получить html-код страницы после входа?

Добрый день

Надеюсь, что не сильно поздно отвечаю (я в отпуске был, и через неделю также продолжу отпуск), но тем не менее
Возможно, стоит просто включить возможность перенаправления в запросе, тогда может быть автоматический переход на страницу после авторизации.
QNetworkRequest request;    // Отправляемый запрос
request.setUrl(url);        // Устанавлвиваем URL в запрос
request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true)


Для Django рекомендую VDS-хостинг TIMEWEB

Спасибо, ща попробую

Наверное я куду-то не туда вставляю

request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true)

код страницы не выдает, нашел вот такой способ. В слот пишем следующий код
void Downloader::replyFinished(QNetworkReply *reply)
{
    if(reply->error() == QNetworkReply::NoError)
    {
        //Получаем код статуса http
        int v = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
        qDebug()<<"v  '"<<v<<"'";
if (v >= 200 && v < 300) //Успешно { //Получаем окончательный ответ QString replyText = reply->readAll(); qDebug()<<"qwer\n"<<replyText; } else if (v >= 300 && v < 400) //Перенаправление { qDebug()<<"asdf\n"; //Получаем URL перенаправления QUrl newUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); //Поскольку URL перенаправления может быть относительным, //мы должны использовать предыдущий, чтобы его разрешить newUrl = reply->url().resolved(newUrl); QNetworkAccessManager *manager = reply->manager(); QNetworkRequest redirection(newUrl); QNetworkReply *newReply = manager->get(redirection); return; //Для вызова следующего запроса } } else { //Error qDebug()<<reply->errorString(); } }

сначала появляется код страницы до регистрации, потом код страницы после регистрации.
З.Ы. Извините, что отвлек от отпуска


Да, ваш вариант тоже может быть вполне подходящим под задачу.

Только проверку кодов я бы сделал через switch case, иначе можно словить вместо редиректа какой-нибудь мусор или ошибку.
switch (v)
{
	case 200:
	case 201:
	{
		 //Получаем окончательный ответ
		QString replyText = reply->readAll();
		qDebug()<<"qwer\n"<<replyText;
		break;
	}
	case 300:
	case 301:
	case 302:
	{
		qDebug()<<"asdf\n";
		//Получаем URL перенаправления
		QUrl newUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
		//Поскольку URL перенаправления может быть относительным,
		//мы должны использовать предыдущий, чтобы его разрешить
		newUrl = reply->url().resolved(newUrl);

		QNetworkAccessManager *manager = reply->manager();
		QNetworkRequest redirection(newUrl);
		QNetworkReply *newReply = manager->get(redirection);

		return; //Для вызова следующего запроса
	}
}

Я думаю, что обрабатывать нужно конкретные редиректы, а не весь диапазон этих редиректов. Неизвестно что может быть например в случае редиректа 306...

Для Django рекомендую VDS-хостинг TIMEWEB

Спасибо

Еще один вопрос. Как в указанном примере на сервер можно передать несколько строк?


Вообще да, почему нет?

Просто что именно под строками подразумеваете?
Также всё зависит от того, как написано API на сервере.
Если вы там REST API написали, которое может разобрать массив строк из JSON, то можно просто подготовить этот массив в JSON и отправить всё пачкой.


Для Django рекомендую VDS-хостинг TIMEWEB

Я пытаюсь получить cookies  и вставить их в повторный запрос. Пробую через QNeworkCookieJar, но пока не получается. Может есть какой пример?

К сожалению с куками не было повода поработать. Так что пока такой информации на сайте нет о QNeworkCookieJar

Для Django рекомендую VDS-хостинг TIMEWEB

разобрался - просто полученные cookies пихаем в наш, уже существующий  слот, правда, программа зацикливается, но это решаемо. Кстати, чем лучше пользоваться для прекращения работы программы при получения ответа от сервера?

void Downloader::replyFinished(QNetworkReply *reply)
{   
    QByteArray data;//Для куков
    QByteArray answ;//сюда пишем ответ от сервера
    QVariant varCookies;//для куков
    QList<QNetworkCookie> cookies;//контейнер с куками

    static int counter = 0;//Просто счетчик чтоб видеть приходит ли ответ и с какого раза

    if(counter < 1)//Чтобы лишний раз не забирать хедеры
    {
        varCookies = reply->header(QNetworkRequest::SetCookieHeader);//Получаем куки
        cookies = varCookies.value<QList<QNetworkCookie>>();//Пихаем куки в контейнер


        
        foreach (QNetworkCookie c, cookies)//Тут переделываем куки в из QNetworkCookie в QBayteArray
        {
            data.append(c.toRawForm());//Получаем значения cookies из списка
            data.append(';');
        }

//        qDebug()<<"data "<<data;
//        qDebug()<<"varCookies"<<varCookies;
//        qDebug()<<"cookies"<<cookies;
    }
    static QByteArray zxcv = data.mid(0, 43);//Копируем  JSESSIONID - не нужно (просто посмотреть)
    //qDebug()<<"cookieArray "<<zxcv;
    QList<QByteArray> reqHeaderReplay = reply->rawHeaderList();//Сюда пишутся все хедеры полученные от сервера
    
    QByteArray reqName, reqValue;//Имя хедера и его значение
    foreach(reqName, reqHeaderReplay)
    {
        reqValue = reply->rawHeader(reqName);//Получаем имя хедера и его значения
        //qDebug()<<reqName<<", "<<reqValue;
    }

    if(reply->error() == QNetworkReply::NoError)
    {
        qDebug()<<counter<<"--------------------------------------------";
        QNetworkRequest requ;//Создаем еще один запрос
        QString sUrlN = "http://novy-adress.by/message";//Новый адрес
        requ.setUrl(sUrlN);
        requ.setHeader(QNetworkRequest::ContentTypeHeader,"application/x-www-form-urlencoded");
        requ.setRawHeader(reqName, reqValue);
        //qDebug()<<"zxcv"<<zxcv;
        QByteArray postDat;//Новый пост запрос
        postDat.append("param1=123&param2=456");//Параметры которые нужно передать

        manager->post(requ, postDat);//Наш новый post-запрос
        qDebug()<<"post-1--post";
        answ = reply->readAll();//Ловим ответ
        qDebug()<<"answer"<<counter<<answ;

        counter++;

        //Получаем код статуса http
        int v = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
        qDebug()<<"v  '"<<v<<"'";
        switch (v)
        {
            case 200:
            case 201:
            {

                //Получаем окончательный ответ
                QString replyText = reply->readAll();//Тут получаем HTML-страницы - осталось с прошлого раза))
                qDebug()<<"200-201\n"<<replyText;
                //QVariant varCookies = reply->header(QNetworkRequest::SetCookieHeader);

                break;
            }
            case 300:
            case 301:
            case 302:
            {
                qDebug()<<"300-301-302\n";
                //Получаем URL перенаправления
                QUrl newUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
                //Поскольку URL перенаправления может быть относительным,
                //мы должны использовать предыдущий, чтобы его разрешить
                newUrl = reply->url().resolved(newUrl);

                QNetworkAccessManager *manager = reply->manager();
                QNetworkRequest redirection(newUrl);
                QNetworkReply *newReply = manager->get(redirection);

//                qDebug()<<"cookies300"<<cookies;
//                qDebug()<<"newReply"<<newReply;
                return; //Для вызова следующего запроса
            }
        }
    }
    else
    {
        //Error
        qDebug()<<reply->errorString();
    }

    //qDebug()<<"counter"<<counter;

    reply->deleteLater();
    if(answ != "")
    {
        return;
    }
}

Вообще, для выхода из программы можно использовать и доступ к инстансу приложения, через qApp->quit()

Также, если у вас есть главное окно приложения, то можно просто его закрыть.

mainwindow->close();

В данном случае, когда не остаётся активных окон, то приложение завершается.

И замечания по вашему коду

Вот это кусок кода бесполезный. Вы в любом случае выходите из метода.

if(answ != "")
{
    return;
}

Также рекомендую делать проверку так

if(!answ.isEmpty())
{
    return;
}

Это сделает более полную проверку на наличие символов в QByteArray.

Не используйте foreach, подробнее в этой статье



Для Django рекомендую VDS-хостинг TIMEWEB

Спасибо

Ответы

Только авторизованные пользователи могут отвечать на форуме.
Пожалуйста, Авторизуйтесь или Зарегистрируйтесь
24 сентября 2018 г. 17:42
edorofeeva

C++ - Тест 001. Первая программа и типы данных

  • Результат 100баллов,
  • Очки рейтинга10
24 сентября 2018 г. 17:37
edorofeeva

C++ - Тест 001. Первая программа и типы данных

  • Результат 66баллов,
  • Очки рейтинга-1
23 сентября 2018 г. 14:38
No Names

C++ - Тест 001. Первая программа и типы данных

  • Результат 60баллов,
  • Очки рейтинга-1
Последние комментарии
25 сентября 2018 г. 15:24
pasagir

Qt/C++ - Урок 006. QSqlQueryModel - Таблицы в Qt с помощью SQL-запросов

Это запись метода которая работает параллельно с БД, данные из парсера поступают в БД и в наш метод одновременно
25 сентября 2018 г. 14:56
pasagir

Qt/C++ - Урок 006. QSqlQueryModel - Таблицы в Qt с помощью SQL-запросов

Как можно динамически отображать данные в таблице? На COM-порт непрерывно приходят данные, я их принимаю сохраняю в БД, а после остановка приема/передачи данные отображаются в таблице. В табли...
25 сентября 2018 г. 10:43
Евгений Легоцкой

Qt/C++ - Урок 017. QGraphicsScene или как работать с графикой в Qt

Прямо так не написано. Хотя соглашусь, что в качестве улучшения вызов данного метода здесь к месту.
25 сентября 2018 г. 10:37
reef425

Qt/C++ - Урок 017. QGraphicsScene или как работать с графикой в Qt

В статье написано, что таймер сработает один раз. Но это не так. Было бы хорошо добавить timer->setSingleShot(true); После инициализации таймера.
24 сентября 2018 г. 15:09
Евгений Легоцкой

Qt Linux - Урок 001. Автозапуск Qt приложения под Linux

А вот здесь у меня есть пример использования supervisor. https://evileg.com/ru/post/3/ Вся статья вам там не интересна, интересен только шаг с настройкой supervisor. Он получается ...
Сейчас обсуждают на форуме
25 сентября 2018 г. 15:57
Евгений_Канусовский@1981

Чтение файлов в python

Вот код: import sys from re import matchfrom vira import *from PyQt5 import QtCore, QtGui, QtWidgetsfrom PyQt5.QtWidgets import (QDialog, QFileDialog, QMessageBox, QLineEdit, QProgr...
25 сентября 2018 г. 13:51
DmitrySD

Трансляция видео с помощью VLC по RTP

Спасибо! Данная команда не дала результата. В итоге сделал трансляцию через ffmpeg. ffmpeg.exe -f gdigrab -framerate 30 -i desktop -vcodec libx264 -preset:v veryfast -b:v 4000k -f...
25 сентября 2018 г. 13:39
Arrow

Настройка Qt Creator для Android

Конечно отпишусь.
25 сентября 2018 г. 12:22
avovana

Автозапуск и авторестарт Qt Gui Application в Linux

Не получается... Решил пробовать скрипт, выполняемый при загрузке. В скрипте вечный цикл по старту программы.
Присоединяйтесь к нам в социальных сетях