【cocos2dx】HttpClient网络访问

版权声明:本文为博主原创文章,转载请标明出处 https://blog.csdn.net/C2681595858/article/details/80773925

一、实验要求

想象你要做一个联网对战的卡牌游戏,你需要 用户注册/登录、用户获取个人信息、用户修改个人信息 等等。该作业就是实现以上几个功能

  • 实现 输入用户名和密码进行注册、登录;注册、登录后应有信息回显 (显示成功/失败,和服务端返回的信息)
  • 实现 获取用户信息
  • (加分项) 实现 修改个人信息
    修改个人信息只是修改“卡组”信息,输入框中直接输入“卡组”的json
    这一功能需要通过cookie认证身份,即在登录后需要记录cookie (enableCookies)
    使用enableCookies非常简单,因此需要在报告中体现 “思考enableCookies的作用” 才能加分

二、源码解析

LoginRegisterScene.cpp


//登录按钮回调函数
void LoginRegisterScene::loginButtonCallback(cocos2d::Ref * pSender) {
  // Your code here
    if (usernameInput->getString() == "" || passwordInput->getString() == "")
    {
        this->messageBox->setString("Login Failed!\n");
        return;
    }
    HttpRequest* request = new HttpRequest();
    request->setRequestType(HttpRequest::Type::POST);
    request->setUrl("http://127.0.0.1:8000/auth");
    request->setResponseCallback(CC_CALLBACK_2(LoginRegisterScene::loginHttpRequestCompleted, this));

    std::string postdata = "{\"username\" : \"" +  usernameInput->getString() + "\",\"password\"  :\""+ passwordInput->getString() + "\"}";
    const char* postdt = postdata.c_str();
    request->setRequestData(postdt, strlen(postdt));
    cocos2d::network::HttpClient::getInstance()->send(request);
    cocos2d::network::HttpClient::getInstance()->enableCookies(nullptr);
    request->release();
}

上面函数需要注意:要加上enableCookies,在服务端,当程序需要为某个客户端的请求创建一个session的时候,服务 器首先检查这个客户端的请求里是否已包含了一个session标识 - 称为 session id(或者cookie),如果已包含一个session id(cookie)则说明以前已经为此客户端创建 过session,服务器就按照session id(cookie)把这个session检索出来使用(如果 检索不到,可能会新建一个),如果客户端请求不包含session id(cookie),则 为此客户端创建一个session并且生成一个与此session相关联的session id(cookie),session id(cookie)的值应该是一个既不会重复,又不容易被找到规律以仿 造的字符串,这个session id(cookie)将被在本次响应中返回给客户端保存。

//注册按钮回调函数
void LoginRegisterScene::registerButtonCallback(Ref * pSender) {
  // Your code here
    if (usernameInput->getString() == "" || passwordInput->getString() == "")
    {
        this->messageBox->setString("Register Failed!\n");
        return;
    }
    HttpRequest* request = new HttpRequest();
    request->setRequestType(HttpRequest::Type::POST);
    request->setUrl("http://127.0.0.1:8000/users");
    request->setResponseCallback(CC_CALLBACK_2(LoginRegisterScene::registerHttpRequestCompleted, this));

    //std::string postdata = "{\"username\" : " + usernameInput->getString()+", \"password\"  :"+ passwordInput->getString() +"}";
    std::string postdata ="{\"username\":\"" + usernameInput->getString() + "\", \"password\":\"" + passwordInput->getString()+"\"}";
    const char* postdt = postdata.c_str();
    request->setRequestData(postdt, strlen(postdt));
    cocos2d::network::HttpClient::getInstance()->send(request);
    request->release();
}

这里需要注意:严格按照PPT上对服务端数据的说明,key值和value都要有引号,所以一定要注意std::string postdata ="{\"username\":\"" + usernameInput->getString() + "\", \"password\":\"" + passwordInput->getString()+"\"}";这句,和注释掉的那句对比一下,那句value值少了引号,导致注册登录看似正常,最后查询时会出错,所以记得value值加引号。

//登录回显函数
void LoginRegisterScene::loginHttpRequestCompleted(HttpClient* sender, HttpResponse* response)
{
    auto buffer = response->getResponseData();
    rapidjson::Document doc;
    doc.Parse(buffer->data(), buffer->size());
    if (doc["status"] == true)
    {
        this->messageBox->setString("Login OK!");
    }
    else
    {
        this->messageBox->setString(std::string("Login Failed!\n") + doc["msg"].GetString());
    }
    return;
}
//注册回显函数
void LoginRegisterScene::registerHttpRequestCompleted(HttpClient* sender, HttpResponse* response)
{
    auto buffer = response->getResponseData();
    rapidjson::Document doc;
    doc.Parse(buffer->data(), buffer->size());
    if (doc["status"] == true)
    {
        this->messageBox->setString("Register OK!");
    }
    else
    {
        this->messageBox->setString(std::string("Register Failed!\n") +  doc["msg"].GetString());
    }
    return;
}

ModifyUserScene.cpp

void ModifyUserScene::putDeckButtonCallback(Ref * pSender) {
  // Your code here
    HttpRequest* request = new HttpRequest();
    request->setRequestType(HttpRequest::Type::PUT);
    request->setUrl("http://127.0.0.1:8000/users");
    request->setResponseCallback(CC_CALLBACK_2(ModifyUserScene::modifyHttpRequestCompleted, this));
    std::string putdata = "{\"deck\":" + deckInput->getString()+"}";
    const char* putdt = putdata.c_str();
    request->setRequestData(putdt, strlen(putdt));
    cocos2d::network::HttpClient::getInstance()->send(request);
    request->release();
}

这里基本上没有难点,注意ppt上对put的json数据格式的要求就可以。

void ModifyUserScene::modifyHttpRequestCompleted(HttpClient* sender, HttpResponse* response)
{
    auto buffer = response->getResponseData();
    rapidjson::Document doc;
    doc.Parse(buffer->data(), buffer->size());
    if (doc["status"] == true)
    {
        this->messageBox->setString("PUT OK!");
    }
    else
    {
        this->messageBox->setString(std::string("PUT Failed!\n") + doc["msg"].GetString());
    }
    return;
}

UsersInfoScene.cpp

void UsersInfoScene::getUserButtonCallback(Ref * pSender) {
  // Your code here
    HttpRequest* request = new HttpRequest();
    request->setRequestType(HttpRequest::Type::GET);
    std::string url = "http://127.0.0.1:8000/users?limit=" + limitInput->getString();
    request->setUrl(url);
    request->setResponseCallback(CC_CALLBACK_2(UsersInfoScene::getUserHttpRequestCompleted, this));
    cocos2d::network::HttpClient::getInstance()->send(request);
    request->release();
}
void UsersInfoScene::getUserHttpRequestCompleted(HttpClient* sender, HttpResponse* response)
{
    auto buffer = response->getResponseData();
    std::string output = "";
    rapidjson::Document doc;
    doc.Parse(buffer->data(), buffer->size());
    if (doc["status"] == true)
    {//不同用户之间的循环
        for (int i = 0; i <doc["data"].Size(); i++)
        {   //一个用户下的循环
            output = output + "Username : " + doc["data"][i]["username"].GetString() + "\n";
            output += "Deck:\n";
            for (int k = 0; k < (doc["data"])[i]["deck"].Size(); k++)
            {
                for (rapidjson::Value::ConstMemberIterator itr = ((doc["data"])[i]["deck"])[k].MemberBegin(); itr != ((doc["data"])[i]["deck"])[k].MemberEnd(); itr++)
                {
                    rapidjson::Value jKey;
                    rapidjson::Value jValue;
                    Document::AllocatorType allocator;
                    jKey.CopyFrom(itr->name, allocator);
                    jValue.CopyFrom(itr->value, allocator);
                    if (jKey.IsString())
                    {
                        std::string name = jKey.GetString();
                        int value = jValue.GetInt();
                        std::stringstream stream;
                        stream << value;
                        std::string values = stream.str();
                        output = output+ "     "+name+':' + values + '\n';
                    }
                }
                output += "     _ _ _\n";
            }
            output += "_ _ _\n";
        }
        this->messageBox->setString(output);
    }
    else
    {
        this->messageBox->setString(std::string("Register Failed!\n") + doc["msg"].GetString());
    }
    return;
}

问题最多的就是这部分,首先要清楚服务端返回的数据格式是什么样的,仔细看PPT中的说明,怎么仔细都不为过。
然后外层循环可以直接用int类型++实现,但内层特别是获取key和value对的时候要注意,此时没有已知的key,所以要用迭代器来遍历整个数组,然后依次取得相应的key和value。取得value后不能直接输出,因为它是int类型直接加在string中输出会出现乱码,所以要将它转化为string类型然后加在string中输出。

三、经验总结

参考链接:

获得key和value
c++解析json数据

实验代码

全部代码

对我来说,这次作业的难点在解析json数据上面,一开始直接用int++循环来处理,走不通,百度求助,看了很多文章介绍直接用*itr处理,行不通,最后看到链接中的那种方法解决了。还有就是要注意json返回出来的value的数据类型。好多次我直接在卡牌数目上用GetString()。导致错误。不同类型用不同函数GetInt(),GetArray()等。

猜你喜欢

转载自blog.csdn.net/C2681595858/article/details/80773925