Qt 5 C++ – Tải file qua mạng với QNetworkAccessManager

4/5 - (40 votes)

Trong phần này chúng ta sẽ học cách gửi các yêu cầu HTTP và nhận file HTML gửi về bằng lớp QNetworkAccessManager.

QNetworkAccessManager

Lớp QNetworkAccessManager cho phép ứng dụng gửi các yêu cầu và nhận trả lời qua mạng. Đối tượng QNetworkAccessManager lưu trữ các phương thức kết nối mạng, cấu hình thường dùng và các thiết lập cần thiết cho các yêu cầu được gửi đi, thông số proxy và cache, các Signal liên quan… Lớp QNetworkAccessManager rất mạnh, gần như bạn chỉ cần tạo một đối tượng QNetworkAccessManager là có thể dùng cho toàn bộ ứng dụng Qt.

Khi bạn tạo một đối tượng QNetworkAccessManager và dùng nó để gửi các yêu cầu qua mạng thì thông điệp gửi về sẽ nằm trong một đối tượng QNetworkReplpy.

Mini Browser

Chúng ta sẽ dùng QNetworkAccessManager để gửi yêu cầu HTTP và lấy về một file HTML.

minibrowser.pro

...
QT += core
QT += gui widgets
QT += webkitwidgets
QT += network
...

Đầu tiên bạn phải chỉ định một số module được dùng trong file .pro bao gồm network, webkitwidgets.

#include <QPushButton>
#include <QGridLayout>
#include <QLineEdit>
#include <QLabel>
#include <QWidget>
#include <QTextBrowser>
#include <QtWebKitWidgets/QWebView>

#include <QVBoxLayout>
#include <QHBoxLayout>

#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>

#include <QObject>

class MiniBrowser : public QWidget
{
    Q_OBJECT
public:
    MiniBrowser(QWidget *parent = 0);

public slots:
    void goToPage();
    void receiveFinishedSignal(QNetworkReply*);
private:
    QPushButton *goBtn;
    QLabel *urlLbl;
    QLineEdit *line;
    QWebView *browser;

    QNetworkAccessManager *manager;
};

Lớp MiniBrowser sẽ là cửa sổ chính.

QWebView *browser;

Lớp QWebView là một widget hỗ trợ hiển thị trang web HTML.

public slots:
    void goToPage();
    void receiveFinishedSignal(QNetworkReply*);

Slot gotoPage() xử lý sự kiện click button. Slot receiveFinishedSignal() xử lý thông điệp trả về của QNetworkAccessManager.

#include "minibrowser.h"
MiniBrowser::MiniBrowser(QWidget *parent) : QWidget(parent)
{
    manager = new QNetworkAccessManager();

    goBtn = new QPushButton("Go", this);
    urlLbl = new QLabel("Url:", this);
    line = new QLineEdit(this);
    browser = new QWebView(this);    

    QVBoxLayout *vbox = new QVBoxLayout(this);
    QHBoxLayout *hbox = new QHBoxLayout(this);

    hbox->addWidget(urlLbl);
    hbox->addWidget(line);
    hbox->addWidget(goBtn);
    vbox->addLayout(hbox);
    vbox->addWidget(browser);

    setLayout(vbox);

    QObject::connect(goBtn, SIGNAL(pressed()), this, SLOT(goToPage()));
    QObject::connect(manager, SIGNAL(finished(QNetworkReply*)), 
                     this, SLOT(receiveFinishedSignal(QNetworkReply*)));
}

void MiniBrowser::goToPage()
{
    QNetworkRequest request(QUrl(this->line->text()));
    manager->get(request);
}

void MiniBrowser::receiveFinishedSignal(QNetworkReply *reply)
{
    if(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute) == 302)
    {
        QUrl url = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
        manager->get(QNetworkRequest(url));
    }
    QByteArray array = reply->readAll();
    QString str = QString::fromUtf8(array.data(), array.size());
    this->browser->setHtml(str);
}

Chúng ta sẽ tạo một giao diện của một browser đơn giản và cài đặt các slot xử lý.

manager = new QNetworkAccessManager();

Tạo một đối tượng QNetworkAccessManager.

QNetworkRequest request(QUrl(this->line->text()));
manager->get(request);

Để tiến hành gửi các lệnh request qua mạng thì chúng ta dùng phương thức get(), phương thức này nhận một đối  tượng QNetworkRequest, đây là lớp lưu trữ các thông tin cấu hình chuẩn cho các giao thức ứng dụng, hàm khởi tạo QNetworkRequest nhận một đối tượng QUrl, QUrl chẳng qua chỉ là một lớp lưu trữ thông tin của một đường dẫn Url bình thường.

QObject::connect(manager, SIGNAL(finished(QNetworkReply*)), 
                     this, SLOT(receiveFinishedSignal(QNetworkReply*)));

Sau khi gọi phương thức get(), QNetworkAccessManager sẽ thực hiện việc gửi yêu cầu và chờ thông điệp trả lời và sẽ thông báo qua SIGNAL finished(QNetworkReply*) với dữ liệu đi kèm là một đối tượng QNetworkReply, chúng ta kết nối signal này với slot receiveFinishedSignal() để nhận lấy dữ liệu truyền về trong QNetworkReply.

if(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute) == 302)
{
    QUrl url = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
    manager->get(QNetworkRequest(url));
}

Bạn có thể sẽ nhận được một mã lỗi 302 nếu vào đường dẫn google.commã này chuyển hướng bạn đến một đường dẫn khác nên mình lấy đường dẫn mới và gửi một yêu cầu khác.

QByteArray array = reply->readAll();
QString str = QString::fromUtf8(array.data(), array.size());
this->browser->setHtml(str);

Bạn có thể lấy toàn bộ nội dung thông điệp qua phương thức QNetworkReply::readAll(), trong trường hợp này đây là một đoạn code HTML, phương thức này trả về một đối tượng QByteArray() nên nếu bạn muốn đọc kiểu text thì phải chuyển nó qua QString bằng phương thức QString::fromUtf8(). Cuối cùng bạn đưa nội dung HTML vô webview bằng phương thức setHtml().

#include <QApplication>
#include "minibrowser.h"
int main(int argc, char *argv[])
{ 
    QApplication a(argc, argv);
    MiniBrowser browser;
    browser.resize(640, 480);
    browser.setWindowTitle("Mini Browser");
    browser.show();
    return a.exec();
}

Untitled

Nội dung HTML trả về có thể sẽ không đầy đủ hoặc lỗi vì chúng ta không thiết lập một số thông số dành cho giao thức HTTP. Trong bài này mình chỉ hướng dẫn các thao tác cơ bản với lớp QNetworkAccessManager.

 

0 0 votes
Article Rating
Subscribe
Thông báo cho tôi qua email khi
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments