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

简介: 在上一篇文章《调用网络API》中,我只讲述了如何直观的使用API接口以及调用API后返回的结果,本文则从程序实现的角度来实现API的调用,当然本程序的实现也是借助于扇贝网的API接口文档http://www.shanbay.com/help/developer/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/ ,在谷歌浏览器的设置中单击开发者选项,然后刷新一下页眉,就会出现如下的界面:
这里写图片描述

然后点击右边的第一个文件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》中提到请求格式)即可。查词及添词的程序实现分别如下:

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();
}

基于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


原文:http://blog.csdn.net/tengweitw/article/details/45932429

作者:nineheadedbird

目录
相关文章
|
5月前
|
安全 Java API
告别繁琐编码,拥抱Java 8新特性:Stream API与Optional类助你高效编程,成就卓越开发者!
【8月更文挑战第29天】Java 8为开发者引入了多项新特性,其中Stream API和Optional类尤其值得关注。Stream API对集合操作进行了高级抽象,支持声明式的数据处理,避免了显式循环代码的编写;而Optional类则作为非空值的容器,有效减少了空指针异常的风险。通过几个实战示例,我们展示了如何利用Stream API进行过滤与转换操作,以及如何借助Optional类安全地处理可能为null的数据,从而使代码更加简洁和健壮。
150 0
|
4月前
|
网络协议 API Windows
MASM32编程调用 API函数RtlIpv6AddressToString,windows 10 容易,Windows 7 折腾
MASM32编程调用 API函数RtlIpv6AddressToString,windows 10 容易,Windows 7 折腾
|
3月前
|
IDE API 定位技术
Python--API编程:IP地址翻译成实际的物理地址
Python--API编程:IP地址翻译成实际的物理地址
83 0
|
4月前
Qt开发
Qt开发
|
4月前
|
开发工具 C++
qt开发技巧与三个问题点
本文介绍了三个Qt开发中的常见问题及其解决方法,并提供了一些实用的开发技巧。
108 0
|
5月前
|
C++
C++ Qt开发:QUdpSocket网络通信组件
QUdpSocket是Qt网络编程中一个非常有用的组件,它提供了在UDP协议下进行数据发送和接收的能力。通过简单的方法和信号,可以轻松实现基于UDP的网络通信。不过,需要注意的是,UDP协议本身不保证数据的可靠传输,因此在使用QUdpSocket时,可能需要在应用层实现一些机制来保证数据的完整性和顺序,或者选择在适用的场景下使用UDP协议。
242 2
|
5月前
|
网络协议 容器
Qt开发网络嗅探器03
Qt开发网络嗅探器03
|
5月前
|
JSON API 数据库
神秘编程力量来袭!Rails 究竟隐藏着怎样的魔力,能构建出强大的 RESTful API?快来一探究竟!
【8月更文挑战第31天】《构建 RESTful API:使用 Rails 进行服务端开发》介绍了如何利用 Ruby on Rails 框架高效构建可扩展的 RESTful API。Rails 采用“约定优于配置”,简化开发流程,通过示例展示了路由定义、控制器设计及模型层交互等内容,帮助开发者快速搭建稳定可靠的服务端。无论小型项目还是大型应用,Rails 均能提供强大支持,提升开发效率。
44 0
|
JavaScript Java Serverless
入门 | 云开发平台1分钟开发一个API
云开发系列课程主要介绍了从入门到精通快速上手Serverless和云开发技术。学习内容涵盖云开发协同、云函数、云数据库、多媒体托管、前后端一体化框架等Serverless Web开发必备知识。希望通过云开发系列课程的学习与实际操作,让大家深入了解Serverless和云开发技术,并加深对阿里云云开发平台和阿里云Serverless产品的理解与认识。 本篇内容作为入门知识,让你在一分钟之内运行起一个Java/NodeJS/Python/PHP任何一门语言的Serverless API ,让你可以在后续的课程中向API添加各种有意思的功能。
入门 | 云开发平台1分钟开发一个API
|
4天前
|
JSON 前端开发 搜索推荐
关于商品详情 API 接口 JSON 格式返回数据解析的示例
本文介绍商品详情API接口返回的JSON数据解析。最外层为`product`对象,包含商品基本信息(如id、name、price)、分类信息(category)、图片(images)、属性(attributes)、用户评价(reviews)、库存(stock)和卖家信息(seller)。每个字段详细描述了商品的不同方面,帮助开发者准确提取和展示数据。具体结构和字段含义需结合实际业务需求和API文档理解。

热门文章

最新文章