# 【Qt編程】基于Qt的詞典開發系列--用戶登錄及API調用的實現
在上一篇文章《[調用網絡API](http://blog.csdn.net/tengweitw/article/details/45484803)》中,我只講述了如何直觀的使用API接口以及調用API后返回的結果,本文則從程序實現的角度來實現API的調用,當然本程序的實現也是借助于扇貝網的API接口文檔[http://www.shanbay.com/help/developer/api/](http://www.shanbay.com/help/developer/api/)。
由[API文檔](http://www.shanbay.com/help/developer/api/)可知,要想調用其API,必須先注冊。因此,我就注冊了,賬戶名為nineheadedbird, 密碼為123456。顯然,我們要查詞,首先必須得登錄該賬戶。如果用瀏覽器,那就很簡單,只需單純的輸入用戶名和密碼就可以了。可實際上,這一操作并不簡單,只是瀏覽器為我們做了這一切。如果我們要通過程序來實現上述功能的話,就需要用到Qt中的get()函數了,而發送請求的內容格式就至關重要了。
##查看請求格式
**我們可以通過瀏覽器來查看請求格式**:首先用谷歌瀏覽器(其他瀏覽器也可以,不過你要百度一下怎么來查看這些格式)打開扇貝網的登錄界面[http://www.shanbay.com/accounts/login/](http://www.shanbay.com/accounts/login/)?,在谷歌瀏覽器的設置中單擊開發者選項,然后刷新一下頁眉,就會出現如下的界面:?

然后**點擊右邊的第一個文件login**,就會出現下面的內容:?

從上圖可以看出,**內容分為三類**:**General、Response Headers、Request Headers**?
在**General**中可以看到**Request Method為GET**(一般還有另一種方式POST,這在Qt中都有對應的函數),Status Code為200表示正常。在Response Headers 中**我們關注的是Set-Cookie中的csrftoken的值**,因為這在我們登錄時需要這個值。**我們最關心的是Request Headers的內容,這部分就是我們請求函數中內容格式**!參考上述的具體內容如下:?

**我們的程序可以寫成如下的方式:**
~~~
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的值、用戶名以及密碼。**具體格式可見下述代碼:**
~~~
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](http://blog.csdn.net/tengweitw/article/details/45484803)》中提到請求格式)即可。**查詞及添詞的程序實現分別如下:**
~~~
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添詞請求。**其結果顯示如下:**

## 程序實現
**下面我們給出具體的程序實現(qt 5版本,使用到網絡類,需要加上QT += network)**:首先建立一個空的qt子項目,然后添加一個名為netWork的類,繼承自QObject,然后再添加一個名為main的源文件,這三個文件的內容分別如下:?
**1、network.h文件**
~~~
#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文件**
~~~
#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文件**
~~~
#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();
}
~~~
- 前言
- <一>--詞典框架設計及成品展示
- <二>--本地詞典的設計
- <三>--開始菜單的設計
- <四>--無邊框窗口的縮放與拖動
- <五>--無邊框窗口的拖動
- <六>--界面美化設計
- <七>--調用網絡API
- <八>--用戶登錄及API調用的實現
- <九>--JSON數據解析
- <十>--國際音標的顯示
- <十一>系統托盤的顯示
- <十二>調用講述人
- <十三>音頻播放
- <十四>自動補全功能
- <十五>html特殊字符及正則表達式
- 后序