0%

【Qt编程】基于Qt的词典开发系列--用户登录及API调用的实现

在上一篇文章《调用网络API》中,我只讲述了如何直观的使用API接口以及调用API后返回的结果,本文则从程序实现的角度来实现API的调用,当然本程序的实现也是借助于扇贝网的API接口文档http://www.shanbay.com/help/developer/api/


API文档可知,要想调用其API,必须先注册。因此,我就注册了,账户名为nineheadedbird, 密码为123456。显然,我们要查词,首先必须得登录该账户。如果用浏览器,那就很简单,只需单纯的输入用户名和密码就可以了。可实际上,这一操作并不简单,只是浏览器为我们做了这一切。如果我们要通过程序来实现上述功能的话,就需要用到Qt中的get()函数了,而发送请求的内容格式就至关重要了。


查看请求格式

我们可以通过浏览器来查看请求格式:首先用谷歌浏览器(其他浏览器也可以,不过你要百度一下怎么来查看这些格式)打开扇贝网的登录界面http://www.shanbay.com/accounts/login/ ,在谷歌浏览器的设置中单击开发者选项,然后刷新一下页眉,就会出现如下的界面:
图1

然后点击右边的第一个文件login,就会出现下面的内容:
图2

从上图可以看出,内容分为三类General、Response Headers、Request Headers
General中可以看到Request Method为GET(一般还有另一种方式POST,这在Qt中都有对应的函数),Status Code为200表示正常。在Response Headers 中我们关注的是Set-Cookie中的csrftoken的值,因为这在我们登录时需要这个值。我们最关心的是Request Headers的内容,这部分就是我们请求函数中内容格式!参考上述的具体内容如下:
图3

我们的程序可以写成如下的方式:

1
2
3
4
5
6
7
8
9
QNetworkRequest request;
request.setUrl(QUrl("http://www.shanbay.com/accounts/login/"));
request.setRawHeader("Accept","text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
request.setRawHeader("Accept-Language","zh-CN,zh;q=0.8");
request.setRawHeader("Cache-Control","max-age=0");
request.setRawHeader("Connection","keep-alive");
request.setRawHeader("Host","www.shanbay.com");
request.setRawHeader("User-Agent","Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.63 Safari/535.7");
http->get(request);

当我们执行上述的请求之后,服务器就会作答,作答的内容就是上面的Response Headers,而我们需要的是Set-Cookie中的csrftoken的值。在Qt中,我们将程序中finished信号与我们定义的槽关联,即每当网络应答结束时,都会发射这个信号,从而触发该槽函数的执行,来处理服务器的应答内容。在程序中,getCookie函数就是来获取csrftoken的值。


用户登录

获得csrftoken的值后,我们就需要实现登录操作了。除了上述的请求格式之外,我们还需要加入csrftoken的值、用户名以及密码。具体格式可见下述代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
QNetworkRequest request;  request.setUrl(QUrl("http://www.shanbay.com/accounts/login/"));
request.setRawHeader("Accept","text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
request.setRawHeader("Accept-Language","zh-CN,zh;q=0.8");
request.setRawHeader("Cache-Control","max-age=0");
request.setRawHeader("Connection","keep-alive");
request.setRawHeader("Host","www.shanbay.com");
request.setRawHeader("User-Agent","Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.63 Safari/535.7");
request.setRawHeader("Origin","http//www.shanbay.com");
request.setRawHeader("Referer","http://www.shanbay.com/accounts/login/");
request.setRawHeader("Host","www.shanbay.com");
request.setRawHeader("Content-Type","application/x-www-form-urlencoded");
QByteArray postData;
postData.append(QString("csrfmiddlewaretoken=%1&").arg(sessionid));//csrftoken的值
postData.append(QString("username=%1&password=%2&").arg(QUrl::toPercentEncoding(username).constData()).arg(password));//用户名及密码
postData.append("login=登录&continue=home&u=1&next=");
request.setHeader(QNetworkRequest::ContentLengthHeader,postData.size());
httpAction=LoginAction;
http->post(request,postData);

调用API

完成登录之后,就可以进行查词和添词操作了。除了上述提到的请求头格式之外,只需要遵守API规范(《调用网络API》中提到请求格式)即可。查词及添词的程序实现分别如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
void netWork::queryWord(const QString &word)//查词操作
{
QNetworkRequest request;
request.setUrl(QUrl("http://www.shanbay.com/api/word/"+word));
request.setRawHeader("Accept","text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
request.setRawHeader("Accept-Charset","GBK,utf-8;q=0.7,*;q=0.3");
request.setRawHeader("Accept-Language","zh-CN,zh;q=0.8");
request.setRawHeader("Cache-Control","max-age=0");
request.setRawHeader("Connection","keep-alive");
request.setRawHeader("Host","www.shanbay.com");
request.setRawHeader("User-Agent","Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.63 Safari/535.7");
httpAction=QueryWordAction;
http->get(request);
}

void netWork::addWord(const QString &word)//添词操作
{
if(word.isEmpty())
qDebug()<<"你的输入有误";
else
{
QNetworkRequest request;
request.setUrl(QUrl("http://www.shanbay.com/api/learning/add/"+word));
request.setRawHeader("Accept","text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
request.setRawHeader("Accept-Charset","GBK,utf-8;q=0.7,*;q=0.3");
request.setRawHeader("Accept-Language","zh-CN,zh;q=0.8");
request.setRawHeader("Cache-Control","max-age=0");
request.setRawHeader("Connection","keep-alive");
request.setRawHeader("Host","www.shanbay.com");
request.setRawHeader("User-Agent","Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.63 Safari/535.7");
httpAction=AddWordAction;
http->get(request);
}
}

完整流程

至此,API调用的各个功能已经实现,下面给出程序的整体思路首先获取csrftoken的值(每次都不同);然后利用用户名、密码及csrftoken的值来登录;接着就可以调用API了。在程序中,每当进行请求,都会在replyfinished函数中用case语句来分别处理这些请求对应的应答。注意,不要连续的进行请求,否则可能发生冲突。在程序中,为了防止冲突,我在connectNet请求后,在其应答处理函数中再进行loginShanbay的登录,然后在其应答函数中进行queryWord查词请求,然后在其对应的应答处理函数中进行addWord添词请求。其结果显示如下:

图4


程序实现

下面我们给出具体的程序实现(qt 5版本,使用到网络类,需要加上QT += network):首先建立一个空的qt子项目,然后添加一个名为netWork的类,继承自QObject,然后再添加一个名为main的源文件,这三个文件的内容分别如下:
1、network.h文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#ifndef NETWORK_H
#define NETWORK_H


#include <QObject>
#include <QtNetwork/QNetworkAccessManager>
#include<QtNetwork/QNetworkReply>
#include<QtNetwork/QNetworkRequest>
#include<QtNetwork/QNetworkCookie>
#include<QtNetwork/QNetworkCookieJar>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonValue>
#include<QString>
#include<QDebug>
#include<QList>
#include<QUrl>
#include<QByteArray>

class netWork : public QObject //由于程序文件直接摘自整个项目文件,所以程序中有关的定义或函数没有使用,但是这个程序可以单独运行
{
Q_OBJECT
public:
explicit netWork(QObject *parent = 0);
// ~netWork();


enum HttpAction{NoAction,NetStudy,GetSessionidAction,LoginAction,QueryWordAction,AddWordAction,AddExampleAction,QueryWordExamplesAction};
HttpAction httpAction;
QNetworkAccessManager * http;
QString sessionid;
QString queryword;//要查询的单词
QString nickname;
QString username;
QString password;
bool isBusy;


QString getCookie(const QString &name);

void loginShanbay();
void queryWord(const QString &word);
void queryExamples(QString learningid);
void connectNet(QString username="nineheadedbird", QString password="123456");
void addWord(const QString &word);

signals://这里的信号都没有用到

void connectSuccess();
void connectFail();
void verifySuccess();
void verifyFail();
void NetState(bool);
public slots:
void replyfinished(QNetworkReply*);

};

#endif // NETWORK_H

2、network.cpp文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
#include "network.h"
#include<QList>
#include<QDesktopServices>
netWork::netWork(QObject *parent) :
QObject(parent)
{
http=new QNetworkAccessManager(this);
http->setCookieJar(new QNetworkCookieJar(this));
connect(http,SIGNAL(finished(QNetworkReply*)),this,SLOT(replyfinished(QNetworkReply*)));//将finished信号与我们定义的槽关联,每当网络应答结束时,都会发射这个信号
isBusy=true;

}

QString netWork::getCookie(const QString &name)//用于获得SessionId
{
foreach(QNetworkCookie cookie , http->cookieJar()->cookiesForUrl(QUrl("http://www.shanbay.com/")))
{
if(cookie.name()==name)
{
qDebug()<<"csrftoken:"<<cookie.value();
return cookie.value();
}
}
return "";
}
void netWork::connectNet(QString username, QString password)//连接网络,使用默认的用户名和密码
{
this->username=username;
this->password=password;
QNetworkRequest request;
request.setUrl(QUrl("http://www.shanbay.com/accounts/login/"));
request.setRawHeader("Accept","text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
request.setRawHeader("Accept-Language","zh-CN,zh;q=0.8");
request.setRawHeader("Cache-Control","max-age=0");
request.setRawHeader("Connection","keep-alive");
request.setRawHeader("Host","www.shanbay.com");
request.setRawHeader("User-Agent","Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.63 Safari/535.7");
httpAction=GetSessionidAction;
http->get(request);
}

void netWork::replyfinished(QNetworkReply *reply)//每当执行网站应答结束后,就会执行该槽函数
{
QVariant status_code=reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
qDebug()<<"code_state="<<status_code;//网络状态,200代表正常,302代表重定向,404:not found等等
if(status_code==QVariant::Invalid)//判断是否连接到网站,即当前设备能否上网
emit NetState(false);
else
emit NetState(true);

switch(httpAction)//根据我们都进行了什么网络请求
{
case NoAction:
break;
case GetSessionidAction://获取SessionId
sessionid=getCookie("csrftoken");
if(!sessionid.isEmpty())
{
emit connectSuccess();
qDebug()<<("已经连接扇贝网,正在验证用户名密码...");
loginShanbay();
}else
{
emit connectFail();

qDebug()<<("Cannot connect to the website!");
}

break;
case LoginAction: //进行登录操作
httpAction=NoAction;
if(0==reply->readAll().size())
{
QString nickname=QUrl::fromPercentEncoding(getCookie("username").toLatin1());
emit verifySuccess();

qDebug()<<"Successfully Login"<<nickname;
queryWord("hello");
}else
{
emit verifyFail();
qDebug()<<"Failed to login!";
}
break;

case QueryWordAction://查词操作
qDebug()<<"----query word----";
qDebug()<<reply->readAll();//读取查词结果

addWord("hello");//添加单词到单词本
break;
case AddWordAction://添词操作
qDebug()<<"---add word----";
qDebug()<<reply->readAll();//返回添加词语的learning_id
break;
default:break;
}
}

void netWork::loginShanbay()//账户密码的登录操作
{
QNetworkRequest request;
request.setUrl(QUrl("http://www.shanbay.com/accounts/login/"));
request.setRawHeader("Accept","text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
request.setRawHeader("Accept-Language","zh-CN,zh;q=0.8");
request.setRawHeader("Cache-Control","max-age=0");
request.setRawHeader("Connection","keep-alive");
request.setRawHeader("Host","www.shanbay.com");
request.setRawHeader("User-Agent","Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.63 Safari/535.7");
request.setRawHeader("Origin","http//www.shanbay.com");
request.setRawHeader("Referer","http://www.shanbay.com/accounts/login/");
request.setRawHeader("Host","www.shanbay.com");
request.setRawHeader("Content-Type","application/x-www-form-urlencoded");
QByteArray postData;
postData.append(QString("csrfmiddlewaretoken=%1&").arg(sessionid));
postData.append(QString("username=%1&password=%2&").arg(QUrl::toPercentEncoding(username).constData()).arg(password));
postData.append("login=登录&continue=home&u=1&next=");
request.setHeader(QNetworkRequest::ContentLengthHeader,postData.size());
httpAction=LoginAction;
http->post(request,postData);

}

void netWork::queryWord(const QString &word)//查词操作
{
QNetworkRequest request;
request.setUrl(QUrl("http://www.shanbay.com/api/word/"+word));
request.setRawHeader("Accept","text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
request.setRawHeader("Accept-Charset","GBK,utf-8;q=0.7,*;q=0.3");
request.setRawHeader("Accept-Language","zh-CN,zh;q=0.8");
request.setRawHeader("Cache-Control","max-age=0");
request.setRawHeader("Connection","keep-alive");
request.setRawHeader("Host","www.shanbay.com");
request.setRawHeader("User-Agent","Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.63 Safari/535.7");
httpAction=QueryWordAction;
http->get(request);
}



void netWork::addWord(const QString &word)//添词操作
{
if(word.isEmpty())
qDebug()<<"你的输入有误";
else
{
QNetworkRequest request;
request.setUrl(QUrl("http://www.shanbay.com/api/learning/add/"+word));
request.setRawHeader("Accept","text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
request.setRawHeader("Accept-Charset","GBK,utf-8;q=0.7,*;q=0.3");
request.setRawHeader("Accept-Language","zh-CN,zh;q=0.8");
request.setRawHeader("Cache-Control","max-age=0");
request.setRawHeader("Connection","keep-alive");
request.setRawHeader("Host","www.shanbay.com");
request.setRawHeader("User-Agent","Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.63 Safari/535.7");
httpAction=AddWordAction;
http->get(request);
}
}

3、main.cpp文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <QApplication>
#include "network.h"

int main(int argc, char *argv[])
{
QApplication a(argc, argv);

netWork *nW = new netWork();
//
nW->connectNet();
// nW->loginShanbay();
// nW->queryWord("hello");
return a.exec();
}

基于Qt的词典开发系列

  1. 词典框架设计及成品展示
  2. 本地词典的设计
  3. 开始菜单的设计
  4. 无边框窗口的缩放与拖动
  5. 无边框窗口的拖动
  6. 界面美化设计
  7. 调用网络API
  8. 用户登录及API调用的实现
  9. JSON数据解析
  10. 国际音标的显示
  11. 系统托盘的显示
  12. 调用讲述人
  13. 音频播放
  14. 自动补全功能
  15. HTML特殊字符及正则表达式
  16. 后序

作品下载地址(发布版):http://download.csdn.net/detail/tengweitw/8548767
作品下载地址(绿色版):http://download.csdn.net/detail/tengweitw/8830495
源码下载地址:http://download.csdn.net/detail/tengweitw/8830503


坚持原创技术分享,您的支持将鼓励我继续创作!