<八>–用户登录及API调用的实现

最后更新于:2022-04-01 07:11:25

# 【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/) ,在谷歌浏览器的设置中单击开发者选项,然后刷新一下页眉,就会出现如下的界面:  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-15_5698c1c803347.jpg) 然后**点击右边的第一个文件login**,就会出现下面的内容:  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-15_5698c1c823cc8.jpg) 从上图可以看出,**内容分为三类**:**General、Response Headers、Request Headers**  在**General**中可以看到**Request Method为GET**(一般还有另一种方式POST,这在Qt中都有对应的函数),Status Code为200表示正常。在Response Headers 中**我们关注的是Set-Cookie中的csrftoken的值**,因为这在我们登录时需要这个值。**我们最关心的是Request Headers的内容,这部分就是我们请求函数中内容格式**!参考上述的具体内容如下:  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-15_5698c1c84763b.jpg) **我们的程序可以写成如下的方式:** ~~~ 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添词请求。**其结果显示如下:** ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-15_5698c1c85d338.jpg) ## 程序实现 **下面我们给出具体的程序实现(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(); } ~~~
';