QHTTP详解

 

QHttp是Qt所提供有关网络的高阶API,可以协助我们进行HTTP协议的进行,QHttp发出请求时是非同步的,请求的过程中会发出相关的Signal,我们可以用Slot来接收这些Signal,并进行相关的处理。

这个HttpGet可以让我们指定文件的URL地址,以HTTP方式取得文件并存储在本地,URL在Qt中以QUrl代表,当文件下载完成时,会发出finished()的Signal,当QHttp所指定的全部请求完成时,会发出done()的Signal,HTTPGet类中自定义的Slot就是用来接收QHttp的done() Signal以进行相关处理的,这可以在HttpGet的实现中看到

 

Qt的QHttp与QFtp在使用上有许多类似的地方,可以在以上的实例中看到一些特性,以下整理出相关的特性:

1) 非阻塞行为,请求时非同步的。

2) 我们可以设定一连串的请求,每个请求都有一个Command ID,QHttp的requestStarted()与requestFinished()等Signal会带有请求的Command ID,我们可以用以追踪骑请求的执行。

3) 在数据传输过程中,有相关的Signal可以追踪进度,像是QHttp的dataReadProgress()、dataSendProgress()等Signal。

4) 支援QIODevice的写入和读取,还有以QByteArray为基础的API。

url

统一资源定位符(URL)是用于完整地描述Internet上网页和其他资源的地址的一种标识方法。

Internet上的每一个网页都具有一个唯一的名称标识,通常称之为URL地址,这种地址可以是本地磁盘,也可以是局域网上的某一台计算机,更多的是Internet上的站点。简单地说,URL就是Web地址,俗称“网址”。

 

URL的一般格式为(带方括号[]的为可选项):

 protocol :// hostname[:port] / path / [;parameters][?query]#fragment

 

以下先示范一个最基本的QHttp使用,程序将设计一个HttpGet类:

HttpGet.h

Cpp代码      

#ifndef HTTPGET_H   

#define HTTPGET_H   

  

#include <QObject>   

class QUrl;   

class QHttp;   

class QFile;   

  

class HttpGet : public QObject {   

      Q_OBJECT   

public:   

       HttpGet(QObject *parent = 0);   

       void downloadFile(const QUrl &url);   

          

signals:         

       void finished();   

          

private slots:   

        void done(bool error);   

           

private:   

        QHttp *http;   

        QFile *file;   

};   

#endif  

 

 这个HttpGet可以让我们指定文件的URL地址,以HTTP方式取得文件并存储在本地,URL在Qt中以QUrl代表,当文件下载完成时,会发出finished()的Signal,当QHttp所指定的全部请求完成时,会发出done()的Signal,HTTPGet类中自定义的Slot就是用来接收QHttp的done() Signal以进行相关处理的,这可以在HttpGet的实现中看到:

HttpGet.cpp:

Cpp代码

#include <QtNetwork>   

#include <QFile>   

#include <iostream>   

#include "HttpGet.h"   

using namespace std;   

  

HttpGet::HttpGet(QObject *parent) : QObject(parent)    

{   

    http = new QHttp(this);   

    connect(http, SIGNAL(done(bool)), this, SLOT(done(bool)));                

}   

void HttpGet::downloadFile(const QUrl &url)   

{   

    QFileInfo fileInfo(url.path());   

    QString fileName = fileInfo.fileName();   

    if(fileName.isEmpty())   

    {   

        fileName = "index.html";                         

    }   

    file = new QFile(fileName);   

    if(!file->open(QIODevice::WriteOnly))   

    {   

        cerr<<"Unable to save the file"<<endl;   

        delete file;   

        file = 0;   

        return;                                        

    }   

    http->setHost(url.host(), url.port(80));   

    http->get(url.path(), file);   

    http->close();   

}   

  

void HttpGet::done(bool error)   

{   

    if(error)   

    {   

        cerr<<"Error: "<<qPrintable(http->errorString())<<endl;            

    }        

    else    

    {   

        cerr<<"File downloaded as "<<qPrintable(file->fileName())<<endl;        

    }   

    file->close();   

    delete file;   

    file = 0;   

       

    emit finished();   

}  

 要使用Qt的网络相关类必须引进QtNetwork,并且必须在pro文件中加入以下这行以在构建过程中使用Qt的网络组件:

Cpp代码

1.        QT += network  

QT += network

 当调用HttpGet类的downloadFile()方法时,程序中使用QUrl的path()来取得路径信息,如果路径信息中没有包括文件名,就使用预设的"index.html"作为请求的对象及下载后存档时的文件名,要使用QHttp来请求文件时,必须使用setHost()来设定主机及端口号信息,接着使用get()方法发出请求,并通知下载的文件要到哪个QFile来存储。

当QHttp所有请求处理完毕后,会发出done()的Signal,程序中将之连接到HttpGet的done()来处理,处理完成后再发出finished的Signal。

以下是个测试类:

Cpp代码

#include <QCoreApplication>   

#include <QUrl>   

#include "HttpGet.h"   

#include <iostream>   

using namespace std;   

int main(int argc, char *argv[])   

{   

    QCoreApplication app(argc, argv);   

    HttpGet getter;   

    getter.downloadFile(QUrl("Http:\\www.iprai.com/index.html"));   

    QObject::connect(&getter, SIGNAL(finished()), &app, SLOT(quit()));   

    return app.exec();   

}  

 

 

在<<C++ GUI Programming With Qt4>>这本书的第十四章介绍了用QHttp::get()函数去下载一个网页数据。但是这个例子只能处理常规的下载,也就是实现http请求中的“GET”请求,而不能实现”POST”请求。举例来说就是,QHttp::get()
能够下载 http://www.google.com/index.html
而不能下载 http://www.cuteqt.com/blog/?feed=rss
因为后者需要的下载方式不一样,可以用另外一个函数QHttp::request()来实现。

假如我们要执行上面第二个地址的请求,写出来的代码应该是下面的样子。

34     http.setHost("www.cuteqt.com/blog");

35     rssfile.setFileName("./feed.list");

36     rssfile.open(QIODevice::WriteOnly | QIODevice::Truncate);

37     QByteArray inputStr("feed=rss");

38     QHttpRequestHeader header("POST", "/blog/");

39     header.setValue("Content-Type", "application/x-www-form-urlencoded");

40     header.setValue("Host", "www.cuteqt.com/blog");

41     requestid=http.request(header,inputStr,&rssfile);

42     http.close();

34:http是QHttp 类型的,设置好要访问的主机
35:rssfile是QFile类型,下载的网页会存放到这个文件里
37:这个inputStr就是我们查询的串,格式可以是key1=var1&key2=var2&key3=var3的格式
38:设置好主机下的请求路径
40:header里的Host值,还是这个主机名
41:前面配置好的参数,正式发出请求,第三个参数类型是QIODevice *,如果不想存到文件里,你也可以用QBuffer。返回值requestid的作用下面会提到。
http.close();

需要注意的是,QHttp中不管是get()还是request()都是异步请求,也就是命令发出后,随即返回。在数据处理完毕的时候会有SIGNAL信号发出。request()处理完毕的信号名叫SIGNAL(requestFinished(int id,bool)),第一个参数id正是和前面request返回的requestid,以此知道是哪一个http请求处理后的返回消息。用以下函数关联信号和槽
connect(&http, SIGNAL(requestFinished(int,bool)), this, SLOT(httpReqDone(int,bool)));

 

通用代码如下:

    QList<QPair<QByteArray, QByteArray> > querylist;
    querylist=url.encodedQueryItems();//返回Query String of URL.
    if(querylist.size()!=0)
    {
        QByteArray querydata;
        querydata.append(querylist[0].first);
        querydata.append('=');
        querydata.append(querylist[0].second);
        for (int i = 1; i < querylist.size(); ++i) {
            querydata.append('&');
            querydata.append(querylist[i].first);
            querydata.append('=');
            querydata.append(querylist[i].second);
        }
        QHttpRequestHeader header("POST", url.path());
        header.setValue("Content-Type", "application/x-www-form-urlencoded");
        header.setValue("Host", url.host());
        http.setHost(url.host());
        http_request_id=http.request(header,querydata,&file);
        qDebug()<<querydata;
        http.close();
    }
    else
    {
        http.setHost(url.host(), url.port(80));
        http.get(url.path(), &file);
        http_request_id=0;
        http.close();
    }

 

阅读更多
换一批

qhttp 下载完的文件保存在哪里?

03-14

一个网站内容下载的类和实现rnrnhttpget.h---------------------------------rnrn#ifndef HTTPGET_Hrnrn#define HTTPGET_Hrnrn#include rnrnclass QUrl;rnrnclass QHttp;rnrnclass QFile;rnrnclass HttpGet : public QObject rnrnQ_OBJECTrnrnpublic:rnrnHttpGet(QObject *parent = 0);rnrnvoid downloadFile(const QUrl &url);rnrnsignals:rnrnvoid finished();rnrnprivate slots:rnrnvoid done(bool error);rnrnprivate:rnrnQHttp *http;rnrnQFile *file;rnrn;rnrn#endifrnrnhttpget.cpp------------------------------------rnrn#include rnrn#include rnrn#include rnrn#include "HttpGet.h"rnrnusing namespace std;rnrnHttpGet::HttpGet(QObject *parent) : QObject(parent) rnrnhttp = new QHttp(this);rnrnconnect(http, SIGNAL(done(bool)), this, SLOT(done(bool)));rnrnrnrnvoid HttpGet::downloadFile(const QUrl &url) rnrnQFileInfo fileInfo(url.path());rnrnQString fileName = fileInfo.fileName();rnrnif (fileName.isEmpty()) rnrnfileName = "index.html";rnrnrnrnfile = new QFile(fileName);rnrnif (!file->open(QIODevice::WriteOnly)) rnrncerr << "Unable to save the file" << endl;rnrndelete file;rnrnfile = 0;rnrnreturn;rnrnrnrnhttp->setHost(url.host(), url.port(80));rnrnhttp->get(url.path(), file);rnrnhttp->close();rnrnrnrnvoid HttpGet::done(bool error) rnrnif (error) rnrncerr << "Error: " << qPrintable(http->errorString()) << endl;rnrn else rnrncerr << "File downloaded as " << qPrintable(file->fileName())rnrn<< endl;rnrnrnrnfile->close();rnrndelete file;rnrnfile = 0;rnrnemit finished();rnrnrnrnmain.cpp------------------------------rnrn#include rnrn#include "mainwindow.h"rnrn#include rnrn#include rnrn#include rnrn#include "HttpGet.h"rnrn#include rnrnint main(int argc, char *argv[])rnrnrnrnQApplication a(argc, argv);rnrnQTextCodec::setCodecForTr(QTextCodec::codecForName("gb18030"));rnrnHttpGet getter;rnrngetter.downloadFile(QUrl("http://lvpengcheng.com.cn/index.htm"));rn//qhttp 下载完的文件保存在哪里了?rnreturn a.exec();rnrn

QHttp GET POST无法工作

09-25

GET 使用Http Json消息体rn/*rn本代码参考 http://blog.csdn.net/lslxdx/article/details/7485297rnrn以下为IE测试通过的URL+传递JSON格式的参数:rnrnhttp://180.169.117.41:8020/OZZOThirdPartyService/TheShanService/TheShanService.ReceiveGPSMessage?receiveStr=rn["HandheldDeviceNumber":"789651","X":50000.0,"Y":41000.0,"SubmitTime":"2013-09-17 13:49:45"]rnrn*/rnrn大致代码如下rn//构造函数rnhttp = new QHttp();rnconnect(http, SIGNAL(done(bool)), this, SLOT(Http_done(bool)));rn//开始GETrnQString URLMethod = "/OZZOThirdPartyService/TheShanService/TheShanService.ReceiveGPSMessage?receiveStr=";rn QString data = "[\"HandheldDeviceNumber\":\"789651\",\"X\":50000.0,\"Y\":41000.0,\"SubmitTime\":\"2013-09-17 13:49:45\"]";rn qDebug("%s",qPrintable(URLMethod + data));rn QHttpRequestHeader header("GET", URLMethod+data);//需要传递的参数直接写在path中rn header.setValue("Host", "180.169.117.41");//必须设置主机IP或名字rn http->setHost("180.169.117.41",QHttp::ConnectionModeHttp,8020);//给QHttp设置主机IP和端口号rn http->request(header);//发送请求rnrnrnrnrn但是done后的结果 :HTTP Error 400. The request is badly formed.rn但是如果我把传递参数data去掉 结果为:消息体为空消息体处理异常 <--说明至少“http://180.169.117.41:8020/OZZOThirdPartyService/TheShanService/TheShanService.ReceiveGPSMessage?receiveStr=”这一块是对的 可是我不理解的是 为什么我的JSON格式的参数数据有问题呢rn用IE直接打开就可以得到TRUE的返回值 改加的括号都没少加 引号也都反义了的 有Qter达人懂?rn rnrnrn

利用QNetworkAccessManager和QHttp完成文件下载问题

03-29

我的源码如下:rn[code=C/C++]// 头文件rn#ifndef SYCHRONIZATION_TASK_Hrn#define SYCHRONIZATION_TASK_Hrnrn#include rn#include rn#include rn#include rn#include rnrnclass SynchronizationTask : public QObjectrnrn Q_OBJECTrnrnpublic:rn SynchronizationTask();rnrn void run();rn void startRequest(QUrl url);rnrnsignals:rn void synchronizationFinish();rn void synchronizationFail(const QString& msg);rnrnprivate slots:rn void httpFinished();rn void httpReadyRead();rnrnprivate:rn QHttp *m_http;rn QString m_state;rn QUrl m_url;rn QNetworkAccessManager m_qnam;rn QNetworkReply *m_reply;rn QFile *m_file;rn int m_httpGetId;rn;rnrn#endif[/code]rn[code=C/C++]// 源文件rn#include "sychronizationtask.h"rn#include rn#include rn#include rnrnSynchronizationTask::SynchronizationTask(HostWindow* host, const QString& state) : rn m_host(host), rn m_state(state)rnrnrnrnrnvoid SynchronizationTask::run()rnrn tryrn rn m_url = tr("http://www.baidu.com");rn QString fileName = QFileInfo(m_url.path()).fileName();rn if (fileName.isEmpty())rn fileName = "index.html";rnrn if (QFile::exists(fileName)) rn QFile::remove(fileName);rn rnrn m_file = new QFile(fileName);rn if (!m_file->open(QIODevice::WriteOnly)) rn delete m_file;rn m_file = 0;rn emit synchronizationFail(tr("Unable to save the file %1: %2.")rn .arg(fileName).arg(m_file->errorString()));rn rnrn // schedule the requestrn startRequest(m_url);rn rn catch(const std::exception &e)rn rn emit synchronizationFail(e.what());rn rn catch(...)rn rn emit synchronizationFail(tr("Unknown exception"));rn rnrnrnvoid SynchronizationTask::startRequest(QUrl url)rnrn tryrn rn QNetworkRequest request;rn request.setUrl(url);rn m_reply = m_qnam.get(request);rn connect(m_reply, SIGNAL(finished()), this, SLOT(httpFinished()));rn connect(m_reply, SIGNAL(readyRead()),this, SLOT(httpReadyRead()));rn rn catch(const std::exception &e)rn rn emit synchronizationFail(e.what());rn rn catch(...)rn rn emit synchronizationFail(tr("Unknown exception"));rn rnrnrnvoid SynchronizationTask::httpFinished()rnrn tryrn rn m_file->flush();rn m_file->close();rnrnrn QVariant redirectionTarget = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute);rn if (m_reply->error()) rn m_file->remove();rn else if (!redirectionTarget.isNull()) rn QUrl newUrl = m_url.resolved(redirectionTarget.toUrl());rn if (QMessageBox::question(m_host, tr("HTTP"),rn tr("Redirect to %1 ?").arg(newUrl.toString()),rn QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) rn m_url = newUrl;rn m_reply->deleteLater();rn m_file->open(QIODevice::WriteOnly);rn m_file->resize(0);rn startRequest(m_url);rn return;rn rn rnrn m_reply->deleteLater();rn m_reply = 0;rn delete m_file;rn m_file = 0;rn emit synchronizationFinish();rn rn catch(const std::exception &e)rn rn emit synchronizationFail(e.what());rn rn catch(...)rn rn emit synchronizationFail(tr("Unknown exception"));rn rnrnrnvoid SynchronizationTask::httpReadyRead()rnrn if (m_file)rn m_file->write(m_reply->readAll());rnrnrn[/code]rnrn程序执行到startRequest没有问题,之后一直没进入httpReadyRead和httpFinished函数。我不知道为什么?rn这个我是按照qt例子中的写的。

没有更多推荐了,返回首页