文章目录
- 1、登录回调以及各种函数的使用
- 1、SdoLoginClient工程中的SdoBase_Initialize3接口
- 2、LoginClient中的Initialize接口
- 3、ProcessResponse调用ProcessLoginResponse传递参数给回调函数使用
- 4、ProcessLoginResponse登录响应接口的使用
- 5、ProcessResponse调用然后根据requtestCode请求码跳转到ProcessLoginResponse接口
- 6、ProcessThread调用ProcessResponse
- 7、ThreadEntry调用ProcessThread
- 2、SdoBase_SsoLogin4举例使用
- 1、SdoBase_SsoLogin4接口调用
- 2、SsoLogin接口调用
1、登录回调以及各种函数的使用
1、SdoLoginClient工程中的SdoBase_Initialize3接口
/**
* 新建SdoBase_Initialize3,增加客户端类型参数thirdLoginExtern:0官方,1联想,2顺网。。。
*/
int SDOAPI SdoBase_Initialize3(const char* serverAddr, const char* backupServerAddr,
int appId, int areaId, int groupId, int locale, int tag, int productId, const char* productVersion,
int customSecurityLevel,
SdoBase_CheckCodeLoginCallback checkCodeLoginCallback,
SdoBase_DynamicLoginCallback dynamicLoginCallback,
SdoBase_FcmLoginCallback fcmLoginCallback,
SdoBase_LoginResultCallback loginResultCallback,
SdoBase_GetDynamicKeyCallback getDynamicKeyCallback,
SdoBase_SendPhoneCheckCodeCallback sendPhoneCheckCodeCallback,
SdoBase_CheckAccounTypeCallback checkAccountCallback,
SdoBase_GetQrCodeCallback getCodeKeyCallback,
SdoBase_GetLoginStateCallback getLoginStatusCallback,
SdoBase_ExtendLoginStateCallback extendLoginStateCallback,
SdoBase_LogoutCallback logoutCallback,
SdoBase_SendPushMessageCallback sendPushMessageCallback,
SdoBaseHandle** handle,
int thirdLoginExtern);
接口调用:把相关回调函数作为参数传入SdoBase_Initialize3接口。
//原来是SdoBase_Initialize,为三方登陆加入识别客户端类型的字段
int nRet = SdoBase_Initialize3(strServerAddr.c_str(), strTcpServerAddr.c_str(),
info.AppID, info.AreaId, info.GroupId, 1, 0, 4, strProductVersion.c_str(), 2, /* 2表示动态密码等级 */
onCheckCodeLoginCallback, onDynamicLoginCallback, onFcmLoginCallback, onLoginResultCallback, onGetDynamicKeyCallback,
onSendPhoneCheckCodeCallback, onCheckAccountCallback, onGetQrCodeCallback, onGetLoginStateCallback, onExtendLoginStateCallback,
onLogoutCallback, onSendPushMessageCallback,
&m_pSdoBaseHandle,thirdLoginExtern);
跳转到SdoLoginClient工程中的SdoBase_Initialize3接口声明:
SdoBase_Initialize3接口定义:
extern "C" int SDOAPI SdoBase_Initialize3(const char* serverAddr, const char* backupServerAddr,
int appId, int areaId, int groupId, int locale, int tag,
int productId, const char* productVersion, int customSecurityLevel,
SdoBase_CheckCodeLoginCallback checkCodeLoginCallback,
SdoBase_DynamicLoginCallback dynamicLoginCallback,
SdoBase_FcmLoginCallback fcmLoginCallback,
SdoBase_LoginResultCallback loginResultCallback,
SdoBase_GetDynamicKeyCallback getDynamicKeyCallback,
SdoBase_SendPhoneCheckCodeCallback sendPhoneCheckCodeCallback,
SdoBase_CheckAccounTypeCallback checkAccountCallback,
SdoBase_GetQrCodeCallback getCodeKeyCallback,
SdoBase_GetLoginStateCallback getLoginStatusCallback,
SdoBase_ExtendLoginStateCallback extendLoginStateCallback,
SdoBase_LogoutCallback logoutCallback,
SdoBase_SendPushMessageCallback sendPushMessageCallback,
SdoBaseHandle** handle,
int thirdLoginExtern
)
{
LoginClient* app = new LoginClient;
*handle = (SdoBaseHandle*)app;
LoginClient::thirdLoginExtern = thirdLoginExtern;
return app->Initialize(serverAddr, backupServerAddr, appId, areaId, groupId, locale, tag,
productId, productVersion, customSecurityLevel,
checkCodeLoginCallback, dynamicLoginCallback, fcmLoginCallback,
loginResultCallback, getDynamicKeyCallback, sendPhoneCheckCodeCallback,
checkAccountCallback, getCodeKeyCallback, getLoginStatusCallback,
extendLoginStateCallback, logoutCallback, sendPushMessageCallback);
}
代码解释:
-
这段代码定义了一个名为
SdoBase_Initialize3
的 C 函数,其目的是初始化一个名为LoginClient
的应用程序客户端对象。该函数接受一系列参数,包括服务器地址、应用程序ID、区域ID、组ID、回调函数等,以及一个输出参数handle
,用于返回初始化后的客户端对象。具体步骤如下:
- 创建一个名为
LoginClient
的客户端对象,并将其指针赋值给handle
,以便调用者可以使用该对象进行后续操作。 - 设置一个静态变量
thirdLoginExtern
,并将其值设置为thirdLoginExtern
参数的值。 - 调用客户端对象的
Initialize
方法,将参数传递给该方法,以完成客户端的初始化过程。 - 返回
Initialize
方法的返回值,该值可能表示初始化是否成功。
总之,这段代码是用于初始化一个应用程序客户端对象,并提供一系列回调函数和配置参数,以便客户端可以与服务器进行通信和身份验证。
- 创建一个名为
2、LoginClient中的Initialize接口
Initialize接口声明:
int Initialize(const char* serverAddr, const char* backupServerAddr,
int appId, int areaId, int groupId, int locale, int tag,
int productId, const char* productVersion, int customSecurityLevel,
SdoBase_CheckCodeLoginCallback checkCodeLoginCallback,
SdoBase_DynamicLoginCallback dynamicLoginCallback,
SdoBase_FcmLoginCallback fcmLoginCallback,
SdoBase_LoginResultCallback loginResultCallback,
SdoBase_GetDynamicKeyCallback getDynamicKeyCallback,
SdoBase_SendPhoneCheckCodeCallback phoneCheckCodeCallback,
SdoBase_CheckAccounTypeCallback checkAccountCallback,
SdoBase_GetQrCodeCallback getCodeKeyCallback,
SdoBase_GetLoginStateCallback loginStatusCallback,
SdoBase_ExtendLoginStateCallback extendLoginStateCallback,
SdoBase_LogoutCallback logoutCallback,
SdoBase_SendPushMessageCallback sendPushMessageCallback
);
Initialize接口定义:
int LoginClient::Initialize(
const char* serverAddr, const char* backupServerAddr,
int appId, int areaId, int groupId, int locale, int tag,
int productId, const char* productVersion, int customSecurityLevel,
SdoBase_CheckCodeLoginCallback checkCodeLoginCallback,
SdoBase_DynamicLoginCallback dynamicLoginCallback,
SdoBase_FcmLoginCallback fcmLoginCallback,
SdoBase_LoginResultCallback loginResultCallback,
SdoBase_GetDynamicKeyCallback getDynamicKeyCallback,
SdoBase_SendPhoneCheckCodeCallback phoneCheckCodeCallback,
SdoBase_CheckAccounTypeCallback checkAccountCallback,
SdoBase_GetQrCodeCallback getQrCodeCallback,
SdoBase_GetLoginStateCallback loginStatusCallback,
SdoBase_ExtendLoginStateCallback extendLoginStateCallback,
SdoBase_LogoutCallback logoutCallback,
SdoBase_SendPushMessageCallback sendPushMessageCallback
)
{
char hostName[100]={0};
ParseHttpAddr(serverAddr, m_requestProcess.m_hostName, m_requestProcess.m_port);
if (backupServerAddr != NULL && strlen(backupServerAddr) > 0)
{
ParseHttpAddr(backupServerAddr, m_requestProcess.m_hostName2, m_requestProcess.m_port2);
}
m_requestProcess.m_appid = appId;
m_requestProcess.m_areaid = areaId;
m_requestProcess.m_groupId = groupId;
m_requestProcess.m_locale = locale;
m_requestProcess.m_tag = tag;
m_requestProcess.m_productId = productId;
m_requestProcess.m_customSecurityLevel = customSecurityLevel;
m_requestProcess.m_deviceId = "\0";
m_requestProcess.m_macId="\0";
if (productVersion != NULL)
m_requestProcess.m_productVersion = productVersion;
m_checkCodeLoginCallback = checkCodeLoginCallback;
m_dynamicLoginCallback = dynamicLoginCallback;
m_fcmLoginCallback = fcmLoginCallback;
m_loginResultCallback = loginResultCallback;
m_getDynamicKeyCallback = getDynamicKeyCallback;
m_phoneCheckCodeCallback = phoneCheckCodeCallback;
m_checkAccountCallback = checkAccountCallback;
m_getCodeKeyCallback = getQrCodeCallback;
m_loginStatusCallback = loginStatusCallback;
m_extendLoginStateCallback = extendLoginStateCallback;
m_logoutCallback = logoutCallback;
m_sendPushMessageCallback = sendPushMessageCallback;
//GetPublicKey();
return 0;
}
代码解释:
-
这段代码是
LoginClient
类的Initialize
方法的定义。该方法用于初始化LoginClient
类的成员变量和回调函数,以便后续可以使用这些信息进行身份验证和与服务器的通信。以下是一些关键操作:- 解析
serverAddr
和backupServerAddr
,从中获取主机名和端口号,并将它们存储在m_requestProcess
对象的成员变量中。 - 设置应用程序ID (
appId
)、区域ID (areaId
)、组ID (groupId
)、地区 (locale
)、标签 (tag
)、产品ID (productId
)、自定义安全级别 (customSecurityLevel
) 等信息,也存储在m_requestProcess
对象的相应成员变量中。 - 将各种回调函数存储在
LoginClient
类的成员变量中,以便后续在身份验证和登录过程中使用。 - 初始化其他相关的成员变量,如设备ID (
m_requestProcess.m_deviceId
)、MAC地址 (m_requestProcess.m_macId
)、产品版本 (m_requestProcess.m_productVersion
) 等。 - 最后,调用
GetPublicKey()
方法,该方法似乎未在提供的代码中包含,但可能用于获取公钥或密钥。
该
Initialize
方法的目的是配置LoginClient
对象,以便它可以与服务器进行通信、身份验证和处理登录过程中的各种操作。 - 解析
3、ProcessResponse调用ProcessLoginResponse传递参数给回调函数使用
void LoginClient::ProcessLoginResponse(int reqeustCode, map<string, string>& keyValues)
{
int resultCode = atoi(keyValues["resultCode"].c_str());
if (reqeustCode == REQ_StaticLogin ||
reqeustCode == REQ_AutoLogin ||
reqeustCode == REQ_PhoneCheckCodeLogin ||
reqeustCode == REQ_CheckCodeLogin ||
reqeustCode == REQ_PushMessageLogin ||
reqeustCode == REQ_CodeKeyLogin ||
reqeustCode == REQ_AccountGroupLogin ||
reqeustCode == REQ_ThirdPartyPollingLogin ||
reqeustCode == REQ_ThirdPartyLogin||
reqeustCode == REQ_WeGameLogin ||
reqeustCode == REQ_QQGameLogin ||
reqeustCode == REQ_LenovoLogin
)
{
m_requestProcess.m_autoLoginSessionKey = keyValues["autoLoginSessionKey"];
m_requestProcess.m_autoLoginMaxAge = keyValues["autoLoginMaxAge"];
}
if (reqeustCode == REQ_CodeKeyLogin)
{
m_requestProcess.m_inputUserId = keyValues["inputUserId"];
}else if (reqeustCode == REQ_FcmLogin)
{
if (resultCode == 0)
{
m_requestProcess.SetFlowId("");
}
}
else
{
m_requestProcess.m_inputUserId = "";
}
string nextAction = keyValues["nextAction"];
if (nextAction == "8")
{
m_requestProcess.m_guid = keyValues["guid"];
int needCheckCode = 1;
const char* url = keyValues["picUrl"].c_str();
int width = 0;
int height = 0;
if(keyValues["imagecodeType"] == "4"){ //极验
needCheckCode = 4;
url = keyValues["gt_url"].c_str();
width = atoi(keyValues["width"].c_str());
height = atoi(keyValues["height"].c_str());
}
if (m_checkCodeLoginCallback != NULL)
{
m_checkCodeLoginCallback(resultCode,Utf8ToGbk(keyValues["failReason"].c_str()).c_str(),url,needCheckCode,width,height,(SdoBaseHandle*)this);
}
SdoBase_CheckCodeLoginCallback callback = (SdoBase_CheckCodeLoginCallback)m_mapCallback["SdoBase_CheckCodeLoginCallback"];
if (callback != NULL)
{
callback(resultCode,Utf8ToGbk(keyValues["failReason"].c_str()).c_str(),url,needCheckCode,width,height,(SdoBaseHandle*)this);
}
}
else if (nextAction == "13" || nextAction == "18"|| nextAction == "100")
{
m_requestProcess.m_guid = keyValues["guid"];
if (nextAction == "13")
m_requestProcess.m_loginType = "1";
else if (nextAction == "18")
m_requestProcess.m_loginType = "2";
else if (nextAction == "100")
m_requestProcess.m_loginType = "3";
if (m_dynamicLoginCallback != NULL)
{
m_dynamicLoginCallback(
resultCode,
Utf8ToGbk(keyValues["failReason"].c_str()).c_str(),
atoi(m_requestProcess.m_loginType.c_str()),
atoi(keyValues["deviceType"].c_str()),
Utf8ToGbk(keyValues["deviceDisplayType"].c_str()).c_str(),
Utf8ToGbk(keyValues["challenge"].c_str()).c_str()
,(SdoBaseHandle*)this
);
}
SdoBase_DynamicLoginCallback callback = (SdoBase_DynamicLoginCallback)m_mapCallback["SdoBase_DynamicLoginCallback"];
if (callback != NULL)
{
callback(
resultCode,
Utf8ToGbk(keyValues["failReason"].c_str()).c_str(),
atoi(m_requestProcess.m_loginType.c_str()),
atoi(keyValues["deviceType"].c_str()),
Utf8ToGbk(keyValues["deviceDisplayType"].c_str()).c_str(),
Utf8ToGbk(keyValues["challenge"].c_str()).c_str()
,(SdoBaseHandle*)this
);
}
}
else if (nextAction == "202")
{
if (resultCode == 0)
{
m_requestProcess.m_tgt = keyValues["tgt"];
if (reqeustCode == REQ_FcmLogin)
{
m_requestProcess.SetFlowId("");
}
}
if (m_fcmLoginCallback != NULL)
{
m_fcmLoginCallback(
resultCode,
Utf8ToGbk(keyValues["failReason"].c_str()).c_str(),
atoi(keyValues["isNew"].c_str())!=0,
(SdoBaseHandle*)this
);
}
SdoBase_FcmLoginCallback callback = (SdoBase_FcmLoginCallback)m_mapCallback["SdoBase_FcmLoginCallback"];
if (callback != NULL)
{
callback(
resultCode,
Utf8ToGbk(keyValues["failReason"].c_str()).c_str(),
atoi(keyValues["isNew"].c_str())!=0,
(SdoBaseHandle*)this
);
}
}
else
{
if (resultCode == 0)
{
m_requestProcess.m_tgt = keyValues["tgt"];
}
if (m_loginResultCallback != NULL)
{
m_loginResultCallback(
resultCode,
Utf8ToGbk(keyValues["failReason"].c_str()).c_str(),
keyValues["sndaId"].c_str(),
keyValues["ticket"].c_str(),
keyValues["accountUpgradeUrl"].c_str(),
keyValues["mobile"].c_str(),
(reqeustCode == REQ_SsoLogin)?"":m_requestProcess.m_autoLoginSessionKey.c_str(),
(reqeustCode == REQ_SsoLogin)?0:atoi(m_requestProcess.m_autoLoginMaxAge.c_str()),
atoi(keyValues["popWindowFlag"].c_str()),
keyValues["redirectURL"].empty()?NULL:keyValues["redirectURL"].c_str(),
m_requestProcess.m_inputUserId.empty()?NULL:m_requestProcess.m_inputUserId.c_str(),
keyValues["mid"].c_str(),
keyValues["noteName"].c_str(),
keyValues["displayAccount"].c_str(),
(reqeustCode == REQ_WeGameLogin)?"310":keyValues["companyId"].c_str(),
atoi(keyValues["isNew"].c_str())!=0,
keyValues["appMid"].c_str(),
keyValues["tgt"].c_str(),
(SdoBaseHandle*)this
);
}
SdoBase_LoginResultCallback callback = (SdoBase_LoginResultCallback)m_mapCallback["SdoBase_LoginResultCallback"];
if (callback != NULL)
{
callback(
resultCode,
Utf8ToGbk(keyValues["failReason"].c_str()).c_str(),
keyValues["sndaId"].c_str(),
keyValues["ticket"].c_str(),
keyValues["accountUpgradeUrl"].c_str(),
keyValues["mobile"].c_str(),
(reqeustCode == REQ_SsoLogin)?"":m_requestProcess.m_autoLoginSessionKey.c_str(),
(reqeustCode == REQ_SsoLogin)?0:atoi(m_requestProcess.m_autoLoginMaxAge.c_str()),
atoi(keyValues["popWindowFlag"].c_str()),
keyValues["redirectURL"].empty()?NULL:keyValues["redirectURL"].c_str(),
m_requestProcess.m_inputUserId.empty()?NULL:m_requestProcess.m_inputUserId.c_str(),
keyValues["mid"].c_str(),
keyValues["noteName"].c_str(),
keyValues["displayAccount"].c_str(),
(reqeustCode == REQ_WeGameLogin)?"310":keyValues["companyId"].c_str(),
atoi(keyValues["isNew"].c_str())!=0,
keyValues["appMid"].c_str(),
keyValues["tgt"].c_str(),
(SdoBaseHandle*)this
);
}
}
}
代码解释:
- 这段代码是
LoginClient
类的ProcessLoginResponse
方法的实现。它用于处理登录请求的响应,根据不同的请求代码 (reqeustCode
),采取不同的操作。以下是一些关键操作:- 从响应中提取
resultCode
,并根据reqeustCode
的不同来判断处理方式。 - 如果请求是一种特定类型的登录请求,如静态登录、自动登录、手机验证码登录等,会提取
autoLoginSessionKey
和autoLoginMaxAge
。 - 如果请求是 CodeKey 登录,会提取
inputUserId
。 - 如果请求是 Fcm 登录且结果码为 0,会清除
m_requestProcess
对象的flowId
。 - 根据
nextAction
的不同值,触发相应的回调函数,并传递结果码、失败原因、URL 等参数。
- 从响应中提取
- 这段代码的目的是根据登录请求的不同类型和响应内容,触发不同的回调函数以通知调用方登录状态和操作结果。根据不同的情况,可以处理验证码、动态登录、Fcm 登录等各种登录方式,并将登录结果和相关信息传递给回调函数。这有助于实现灵活的身份验证和登录逻辑。
4、ProcessLoginResponse登录响应接口的使用
ProcessLoginResponse函数声明:
void ProcessLoginResponse(int reqeustCode, map<string, string>& keyValues);
请求码的枚举:
enum RequestCode
{
REQ_GetDynamicKey,
REQ_StaticLogin,
REQ_AutoLogin,
REQ_CheckCodeLogin,
REQ_FcmLogin,
REQ_SsoLogin,
REQ_PhoneCheckCodeLogin,
REQ_CodeKeyLogin,
REQ_DynamicLogin,
REQ_DynamicLoginVoice,
REQ_Logout,
REQ_CheckAccountType,
REQ_SendPhoneCheckCode,
REQ_GetQrCode,
REQ_GetLoginStatus,
REQ_ExtendLoginState,
REQ_SendPushMessage,
REQ_PushMessageLogin,
REQ_RltLogin,
REQ_GetPushMessageStatus,
REQ_GetAccountInfo,
REQ_GetLoginHistory,
REQ_GetPublicKey,
REQ_GetPromotionInfo,
REQ_PromotionInfoConfirm,
REQ_GetClientVKey,
REQ_SendUserAccount,
REQ_SendPushMessageVerifyCheckCode,
REQ_GetAccountGroup,
REQ_AccountGroupLogin,
REQ_ThirdPartyPollingLogin,
REQ_ThirdPartyLogin,
REQ_FastLogin,
REQ_CancelPushMessageLogin,
REQ_GetSessionIdStates,
REQ_KickoffVerify,
REQ_KickOffVerifyCheckCode,
REQ_KickoffAccount,
REQ_GetLoginUserInfo,
REQ_GetLoginAreaInfo,
REQ_SetLoginUserInfo,
//WeGame登陆请求标识
REQ_WeGameLogin,
//联想登陆请求标识
REQ_LenovoLogin,
//云游戏登陆请求标识
REQ_CloudGameLogin,
//咪咕短信发送请求标识
REQ_SendMiGuSms,
//短信发送请求标识
REQ_SendSms,
//验证Captcha后发送短信请求标识
REQ_CheckCodeToSendSms,
//短信登录请求标识
REQ_SmsLogin,
//获取用户隐私配置请求标识
REQ_UserPrivacyConfig,
REQ_FaceVerifyInit,
REQ_FaceCodeResult,
REQ_FaceSendAction,
REQ_GetTicket,
REQ_CreateWeGameOrder,
REQ_WeGameStatus,
REQ_CreateLxOrder,
REQ_UeInitClient,
//QQGame登陆请求标识
REQ_QQGameLogin,
REQ_UeReport,
REQ_CreateQQGameOrder,
REQ_QQGameIsLogin,
REQ_SteamPayResult,
REQ_SteamChannelPayResult,
REQ_CreateSteamChannelOrder
};
代码解释:
- 这是一个枚举类型
RequestCode
,其中列出了不同类型的请求标识。这些请求标识通常用于区分不同的网络请求或操作,以便在程序中根据不同类型的请求采取相应的操作和处理。每个标识都有一个唯一的整数值,用于标识请求的种类。这些请求类型可以包括登录请求、验证码请求、推送消息请求、获取信息请求等等,根据具体的应用场景和需求进行定义和使用。请求码的意义:REQ_GetDynamicKey
: 获取动态密钥请求。REQ_StaticLogin
: 静态登录请求,通常是常规的用户名和密码登录。REQ_AutoLogin
: 自动登录请求。REQ_CheckCodeLogin
: 验证码登录请求,通常需要用户输入验证码。REQ_FcmLogin
: FCM登录请求,用于特定登录方式。REQ_SsoLogin
: 单点登录请求,用于单点登录验证。REQ_PhoneCheckCodeLogin
: 通过手机验证码登录请求。REQ_CodeKeyLogin
: 使用特定代码键登录请求。REQ_DynamicLogin
: 动态登录请求。REQ_DynamicLoginVoice
: 动态登录的语音验证请求。REQ_Logout
: 注销登录请求。REQ_CheckAccountType
: 检查账户类型请求。REQ_SendPhoneCheckCode
: 发送手机验证码请求。REQ_GetQrCode
: 获取二维码请求。REQ_GetLoginStatus
: 获取登录状态请求。REQ_ExtendLoginState
: 扩展登录状态请求。REQ_SendPushMessage
: 发送推送消息请求。REQ_PushMessageLogin
: 推送消息登录请求。REQ_RltLogin
: RLT登录请求。REQ_GetPushMessageStatus
: 获取推送消息状态请求。REQ_GetAccountInfo
: 获取账户信息请求。REQ_GetLoginHistory
: 获取登录历史请求。REQ_GetPublicKey
: 获取公钥请求。REQ_GetPromotionInfo
: 获取推广信息请求。REQ_PromotionInfoConfirm
: 确认推广信息请求。REQ_GetClientVKey
: 获取客户端VKey请求。REQ_SendUserAccount
: 发送用户账户请求。REQ_SendPushMessageVerifyCheckCode
: 发送推送消息验证码请求。REQ_GetAccountGroup
: 获取账户组请求。REQ_AccountGroupLogin
: 账户组登录请求。REQ_ThirdPartyPollingLogin
: 第三方轮询登录请求。REQ_ThirdPartyLogin
: 第三方登录请求。REQ_FastLogin
: 快速登录请求。REQ_CancelPushMessageLogin
: 取消推送消息登录请求。REQ_GetSessionIdStates
: 获取会话ID状态请求。REQ_KickoffVerify
: 踢出验证请求。REQ_KickOffVerifyCheckCode
: 踢出验证并检查验证码请求。REQ_KickoffAccount
: 踢出账户请求。REQ_GetLoginUserInfo
: 获取登录用户信息请求。REQ_GetLoginAreaInfo
: 获取登录区域信息请求。REQ_SetLoginUserInfo
: 设置登录用户信息请求。
- 这些请求类型通常用于不同的用户身份验证、授权、会话管理等操作。具体的含义和操作细节可能根据应用程序和业务逻辑而有所不同。
关于各种请求码相关函数的注册:
LoginClient::LoginClient()
{
m_httpThread = new HttpThread(this);
m_requestProcess.m_timeout = 10000;
m_requestProcess.m_timeout2 = 10000;
m_checkCodeLoginCallback = NULL;
m_dynamicLoginCallback = NULL;
m_fcmLoginCallback = NULL;
m_loginResultCallback = NULL;
m_phoneCheckCodeCallback = NULL;
m_checkAccountCallback = NULL;
m_getCodeKeyCallback = NULL;
m_loginStatusCallback = NULL;
m_extendLoginStateCallback = NULL;
m_getPushMessageStatusCallback = NULL;
m_getAccountInfoCallback = NULL;
m_getLoginHistoryCallback = NULL;
m_getSessionIdStatesCallBack = NULL;
m_callbackKickoffAccountVerify = NULL;
m_callbackKickoffAccountResult = NULL;
m_getLoginUserInfoCallback = NULL;
m_setLoginUserInfoCallback = NULL;
m_getLoginAreaInfoCallback = NULL;
m_UserPrivacyConfigCallback=NULL;
m_FaceVerifyInitCallback=NULL;
m_GetFaceCodeResultCallback=NULL;
m_SendActionCallback=NULL;
m_mapResponseFunc[REQ_GetDynamicKey] = &LoginClient::ProcessGetDynamicKeyResponse;
m_mapResponseFunc[REQ_StaticLogin] = &LoginClient::ProcessLoginResponse;
m_mapResponseFunc[REQ_AutoLogin] = &LoginClient::ProcessLoginResponse;
m_mapResponseFunc[REQ_CheckCodeLogin] = &LoginClient::ProcessLoginResponse;
m_mapResponseFunc[REQ_FcmLogin] = &LoginClient::ProcessLoginResponse;
m_mapResponseFunc[REQ_SsoLogin] = &LoginClient::ProcessLoginResponse;
//WeGame登录请求
m_mapResponseFunc[REQ_WeGameLogin] = &LoginClient::ProcessLoginResponse;
//QQGame登录请求
m_mapResponseFunc[REQ_QQGameLogin] = &LoginClient::ProcessLoginResponse;
//Lenovo登录请求
m_mapResponseFunc[REQ_LenovoLogin] = &LoginClient::ProcessLoginResponse;
//云游戏登录请求
m_mapResponseFunc[REQ_CloudGameLogin] = &LoginClient::ProcessLoginResponse;
//短信登录请求
m_mapResponseFunc[REQ_SmsLogin] = &LoginClient::ProcessLoginResponse;
m_mapResponseFunc[REQ_FastLogin] = &LoginClient::ProcessLoginResponse;
m_mapResponseFunc[REQ_PhoneCheckCodeLogin] = &LoginClient::ProcessLoginResponse;
m_mapResponseFunc[REQ_CodeKeyLogin] = &LoginClient::ProcessLoginResponse;
m_mapResponseFunc[REQ_DynamicLogin] = &LoginClient::ProcessLoginResponse;
m_mapResponseFunc[REQ_DynamicLoginVoice] = &LoginClient::ProcessLoginResponse;
m_mapResponseFunc[REQ_CheckAccountType] = &LoginClient::ProcessCheckAccoutTypeResponse;
m_mapResponseFunc[REQ_SendPhoneCheckCode] = &LoginClient::ProcessSendPhoneCheckCodeResponse;
m_mapResponseFunc[REQ_GetQrCode] = &LoginClient::ProcessGetQrCodeResponse;
m_mapResponseFunc[REQ_GetLoginStatus] = &LoginClient::ProcessGetLoginStatusResponse;
m_mapResponseFunc[REQ_ExtendLoginState] = &LoginClient::ProcessExtendLoginStateResponse;
m_mapResponseFunc[REQ_Logout] = &LoginClient::ProcessLogoutResponse;
m_mapResponseFunc[REQ_PushMessageLogin] = &LoginClient::ProcessLoginResponse;
m_mapResponseFunc[REQ_SendPushMessage] = &LoginClient::ProcessSendPushMessageResponse;
m_mapResponseFunc[REQ_SendPushMessageVerifyCheckCode] = &LoginClient::ProcessSendPushMessageResponse;
m_mapResponseFunc[REQ_RltLogin] = &LoginClient::ProcessLoginResponse;
m_mapResponseFunc[REQ_GetPushMessageStatus] = &LoginClient::ProcessGetPushMessageStatusResponse;
m_mapResponseFunc[REQ_GetAccountInfo] = &LoginClient::ProcessGetAccountInfoResponse;
m_mapResponseFunc[REQ_GetLoginHistory] = &LoginClient::ProcessGetLoginHistoryResponse;
m_mapResponseFunc[REQ_GetLoginUserInfo] = &LoginClient::ProcessGetLoginUserInfoResponse;
m_mapResponseFunc[REQ_SetLoginUserInfo] = &LoginClient::ProcessSetLoginUserInfoResponse;
m_mapResponseFunc[REQ_GetLoginAreaInfo] = &LoginClient::ProcessGetLoginAreaInfoResponse;
m_mapResponseFunc[REQ_GetPublicKey] = &LoginClient::ProcessGetPublicKeyResponse;
// m_mapResponseFunc[REQ_GetGuid] = &LoginClient::ProcessGetGuidResponse;
m_mapResponseFunc[REQ_GetPromotionInfo] = &LoginClient::ProcessGetPromotionInfoResponse;
m_mapResponseFunc[REQ_PromotionInfoConfirm] = &LoginClient::ProcessPromotionInfoConfirmResponse;
m_mapResponseFunc[REQ_GetClientVKey] = &LoginClient::ProcessGetClientVKeyResponse;
m_mapResponseFunc[REQ_SendUserAccount] = &LoginClient::ProcessSendUserAccountResponse;
m_mapResponseFunc[REQ_GetAccountGroup] = &LoginClient::ProcessGetAccountGroupResponse;
m_mapResponseFunc[REQ_AccountGroupLogin] = &LoginClient::ProcessLoginResponse;
m_mapResponseFunc[REQ_ThirdPartyPollingLogin] = &LoginClient::ProcessLoginResponse;
m_mapResponseFunc[REQ_ThirdPartyLogin] = &LoginClient::ProcessLoginResponse;
m_mapResponseFunc[REQ_CancelPushMessageLogin] = &LoginClient::ProcessCancelPushMessageResponse;
m_mapResponseFunc[REQ_GetSessionIdStates] = &LoginClient::ProcessGetSessionIdStateResponse;
m_mapResponseFunc[REQ_KickoffVerify] = &LoginClient::ProcessKickoffVerifyResponse;
m_mapResponseFunc[REQ_KickOffVerifyCheckCode] = &LoginClient::ProcessKickoffVerifyResponse;
m_mapResponseFunc[REQ_KickoffAccount] = &LoginClient::ProcessKickoffResultResponse;
m_mapResponseFunc[REQ_SendMiGuSms] = &LoginClient::ProcessSendMiGuSmsRequestResponse;
m_mapResponseFunc[REQ_SendSms] = &LoginClient::ProcessSendSmsRequestResponse;
m_mapResponseFunc[REQ_CheckCodeToSendSms] = &LoginClient::ProcessCheckCodeToSendSmsRequestResponse;
m_mapResponseFunc[REQ_UserPrivacyConfig] = &LoginClient::ProcessUserPrivacyConfigRequestResponse;
m_mapResponseFunc[REQ_FaceVerifyInit] = &LoginClient::ProcessFaceVerifyInitRequestResponse;
m_mapResponseFunc[REQ_FaceCodeResult] = &LoginClient::ProcessGetFaceCodeResultRequestResponse;
m_mapResponseFunc[REQ_FaceSendAction] = &LoginClient::ProcessSendActionRequestResponse;
m_mapResponseFunc[REQ_GetTicket] = &LoginClient::ProcessGetTicketRequestResponse;
m_mapResponseFunc[REQ_CreateWeGameOrder] = &LoginClient::ProcessCreateWeGameOrderRequestResponse;
m_mapResponseFunc[REQ_WeGameStatus] = &LoginClient::ProcessWeGameStatusRequestResponse;
m_mapResponseFunc[REQ_CreateLxOrder] = &LoginClient::ProcessCreateLxOrderRequestResponse;
m_mapResponseFunc[REQ_UeInitClient] = &LoginClient::ProcessUeInitClientRequestResponse;
m_mapResponseFunc[REQ_CreateQQGameOrder] = &LoginClient::ProcessCreateQQGameOrderRequestResponse;
m_mapResponseFunc[REQ_QQGameIsLogin] = &LoginClient::ProcessQQGameIsLoginRequestResponse;
m_mapResponseFunc[REQ_CreateSteamChannelOrder] = &LoginClient::ProcessCreateSteamChannelOrderRequestResponse;
m_waitEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
m_isPushMessageCheckCode = false;
}
代码解释:
-
这段代码是
LoginClient
类的构造函数,用于初始化LoginClient
对象。以下是它的主要操作:-
创建
HttpThread
对象:m_httpThread
是HttpThread
类的实例,它用于处理 HTTP 请求。 -
设置超时时间:
m_requestProcess.m_timeout
和m_requestProcess.m_timeout2
分别设置了两个超时时间,均为 10000 毫秒(10 秒)。 -
初始化回调函数:该构造函数初始化了多个回调函数的成员变量,例如
m_checkCodeLoginCallback
、m_dynamicLoginCallback
、m_fcmLoginCallback
等等。这些回调函数用于处理不同类型的登录和验证请求的响应。 -
初始化请求类型到响应处理函数的映射:
m_mapResponseFunc
是一个映射,将不同的请求类型与处理它们响应的成员函数绑定在一起。例如,REQ_StaticLogin
对应到ProcessLoginResponse
函数。-
初始化请求类型到响应处理函数的映射是一种机制,它用于将不同种类的请求与相应的处理函数关联起来,以便在收到响应时能够根据请求的类型自动选择正确的处理函数来处理响应数据。
-
**在这段代码中,
m_mapResponseFunc
是一个数据结构,可能是一个映射(例如,使用C++的std::map
或std::unordered_map
),它将请求类型(通常是一个枚举值)映射到相应的处理函数。**每个处理函数负责处理特定类型请求的响应数据。这是一种非常灵活的方式,可以根据请求类型来选择不同的处理逻辑。-
举个例子,如果系统接收到一个登录请求,可以通过该请求的类型(比如
REQ_StaticLogin
)查找到相应的处理函数(ProcessLoginResponse
),然后将响应数据传递给这个函数来进行处理。这允许系统动态地调用适当的处理函数,以处理不同类型的请求。 -
这个映射的设置通常在构造函数中进行,以确保在对象创建时建立请求类型到处理函数的关联。这使得代码更具可维护性和可扩展性,因为可以轻松地添加新的请求类型和相应的处理函数,而无需大规模修改现有的代码。
-
这种通过请求相关枚举值映射到相关函数的方法通常使用了函数指针、函数对象或者回调函数的概念,是一种在C/C++中常见的技术。这种方法之所以有效,是因为在C/C++中,函数是一等公民,可以被视为数据,可以作为参数传递、返回值、存储在数据结构中等。下面是为什么这种方法能够实现的原因:
- 函数指针:在C/C++中,您可以声明指向函数的指针,这允许您将函数的地址存储在变量中。枚举值通常被用作索引,来查找与特定请求类型相关的函数指针。
- 映射表:开发人员创建了一个映射表,通常是一个关联容器(如
std::map
或std::unordered_map
),其中枚举值作为键,与之相关的函数指针作为值。这样,您可以根据请求类型查找并调用相应的函数。 - 动态分派:通过查找映射表并根据请求类型调用相关函数,实现了动态分派。这意味着在运行时根据实际请求类型来选择要执行的函数,而不需要硬编码条件语句。
- 可扩展性:当需要添加新的请求类型时,只需在映射表中添加新的键-值对,无需修改已有的代码。这使得系统更易于扩展。
- 逻辑解耦:将请求类型与处理函数分开存储,使代码更加模块化,提高了可读性和维护性。每个函数负责特定请求类型的处理,这种结构降低了复杂性。
- 静态类型检查:在编译时,编译器会检查函数指针的类型是否与函数签名匹配,因此能够捕获一些类型错误。
-
总之,通过将请求相关的枚举值映射到相关函数,您可以使用C/C++的灵活性和函数指针的特性来实现动态的请求分发,这种方法在处理多种请求类型的系统中非常有用。
-
当你的请求中传递了
REQ_StaticLogin
的枚举值,系统能够跳转到对应的逻辑实现函数的原因如下:- 映射表: 通常在系统初始化时,开发人员会创建一个映射表(可以是哈希表、字典或其他数据结构),将每个请求类型的枚举值与相应的逻辑实现函数关联起来。这个映射表充当了一个查找请求类型的索引,根据请求类型找到相应的函数指针。
- 请求类型:
REQ_StaticLogin
是一个请求类型的枚举值,它标识了你的请求的种类或目的。在系统内部,这个枚举值被用作一个标识,系统知道这是一个登录请求,而不是其他种类的请求。 - 枚举值作为索引: 系统将
REQ_StaticLogin
的枚举值用作索引,查找映射表,以确定与之相关的逻辑实现函数。 - 函数指针: 在映射表中,与
REQ_StaticLogin
枚举值相关联的函数指针指向了实际的逻辑实现函数。这个函数指针告诉系统在处理REQ_StaticLogin
请求时应该执行哪个函数。 - 动态分发: 当系统接收到
REQ_StaticLogin
请求时,它查找映射表,找到关联的函数指针,然后调用这个函数。这就是为什么能够跳转到对应逻辑实现函数的原因。
-
这个设计模式允许系统在不改变核心代码的情况下轻松扩展,只需要添加新的请求类型到映射表的映射关系,而不需要修改已有的逻辑。这提供了可维护性和可扩展性,同时使代码更易理解,因为每个逻辑实现函数只负责特定类型的请求处理。
-
这种将请求类型映射到逻辑实现函数的模式通常被称为"命令模式"(Command Pattern)。命令模式是一种行为设计模式,它允许你将一个请求封装成一个独立的对象,从而可以将客户端请求与接收者解耦。在这种情况下,请求类型充当命令,而映射表中的函数指针则是命令的具体实现。
-
命令模式有助于实现松耦合,提高可维护性和可扩展性。它允许你轻松添加新的命令(请求类型)和新的命令处理逻辑(函数实现),同时保持原有的代码不受影响。这是一种非常有用的设计模式,特别适合需要处理多种类型请求的应用程序。
-
命令模式是一种行为设计模式,它将请求封装为一个独立的对象,从而允许你将客户端与接收者解耦。下面是一个简单的命令模式的示例,其中我们将创建一个遥控器应用程序,通过不同的按钮来控制不同的设备。
- 首先,我们定义命令接口和一些具体的命令类:
#include <iostream> // 命令接口 class Command { public: virtual void execute() = 0; }; // 具体的电灯命令 class LightOnCommand : public Command { public: LightOnCommand(Light& light) : light(light) {} void execute() override { light.turnOn(); } private: Light& light; }; // 具体的电视命令 class TVOffCommand : public Command { public: TVOffCommand(TV& tv) : tv(tv) {} void execute() override { tv.turnOff(); } private: TV& tv; }; // 电灯和电视接收者 class Light { public: void turnOn() { std::cout << "Light is on." << std::endl; } void turnOff() { std::cout << "Light is off." << std::endl; } }; class TV { public: void turnOn() { std::cout << "TV is on." << std::endl; } void turnOff() { std::cout << "TV is off." << std::endl; } };
- 然后,我们创建一个遥控器类,它可以接受不同的命令并执行它们:
// 遥控器 class RemoteControl { public: void setCommand(Command* command) { this->command = command; } void pressButton() { command->execute(); } private: Command* command; }; int main() { Light livingRoomLight; TV livingRoomTV; LightOnCommand lightOn(livingRoomLight); TVOffCommand tvOff(livingRoomTV); RemoteControl remote; remote.setCommand(&lightOn); remote.pressButton(); // 打开电灯 remote.setCommand(&tvOff); remote.pressButton(); // 关闭电视 return 0; }
- 在这个示例中,我们使用了命令模式,遥控器接受不同的命令,并在按下按钮时执行它们,而不需要了解具体的设备或命令的实现。这样可以很容易地扩展新的命令和设备,同时保持客户端代码的简洁性。
-
-
-
-
-
-
-
创建事件对象: 通过
::CreateEvent
创建了一个事件对象m_waitEvent
,用于线程同步,此事件最初为非信号状态,后续可以用SetEvent
将其设置为信号状态,或者用ResetEvent
将其设置为非信号状态。 -
设置其他成员变量的初始状态:这段代码还设置了一些其他成员变量的初始状态,如
m_isPushMessageCheckCode
初始化为false
。
-
-
总的来说,该构造函数用于初始化
LoginClient
对象的各种属性,为后续的登录和验证请求以及响应处理做好准备。
5、ProcessResponse调用然后根据requtestCode请求码跳转到ProcessLoginResponse接口
函数声明:
void ProcessResponse(int result, int requestCode, const string& response,
const vector<string>& vecCookies, bool isUrl2);C
函数定义:
//
// response
void LoginClient::ProcessResponse(int result, int requestCode, const string& response,
const vector<string>& vecCookies, bool isUrl2)
{
map<string, string> keyValues;
ResponseProcess::Process(result, requestCode, response, vecCookies, keyValues);
map<int, ResponseProcessFunc>::iterator iterFunc = m_mapResponseFunc.find(requestCode);
if (iterFunc == m_mapResponseFunc.end())
{
return;
}
if (isUrl2)
{
keyValues["isUrl2"] = "true";
}
if (m_waitEvent)
{
if (WaitForSingleObject(m_waitEvent, 0) != WAIT_OBJECT_0)
{
SetEvent(m_waitEvent);
}
}
m_mapRespParams = keyValues;
MapToMap(m_mapValList, keyValues);
(this->*(iterFunc->second))(requestCode, keyValues);
}
代码解释:
-
这是一个C++代码片段,它处理响应信息。在这个代码中,主要是处理来自服务器的响应,并根据请求代码(
requestCode
)执行相应的处理函数。下面是这段代码的主要功能:-
首先,它将响应信息(
response
)、请求代码(requestCode
)、Cookie 等信息传递给ResponseProcess::Process
函数进行处理,将处理后的结果存储在keyValues
中。-
ResponseProcess::Process
接口:-
接口声明:
class ResponseProcess { public: static int Process(int result, int requestCode, const string& respose, const vector<string>& vecCookies, map<string, string>& keyValues); };
-
这是一个名为
ResponseProcess
的类,具有一个名为Process
的静态成员函数。这个类似乎用于处理响应数据并将其解析为关键数值对(key-value pairs)。以下是这个类的主要成员和函数的说明:
-
Process
函数:这是一个静态函数,用于处理响应数据。它接受以下参数:result
:表示处理结果的整数值,可能用于表示请求是否成功。requestCode
:表示请求的代码或标识。response
:包含来自服务器的响应数据的字符串。vecCookies
:一个字符串向量,包含响应中的 Cookie 信息。keyValues
:一个引用参数,将被用于存储解析后的关键数值对。
这个函数的主要功能是解析
response
中的数据,将其解析为键值对(key-value pairs),并将这些键值对存储在keyValues
参数中。它还可能根据result
和requestCode
的值执行不同的处理逻辑,但具体的处理逻辑需要查看实际的函数实现。
这个类和函数的设计用途似乎是为了将响应数据解析为可用的信息,以便后续的处理。可能会有不同的请求和响应处理函数,而
ResponseProcess
类的Process
函数被用来提取和准备数据以供这些处理函数使用。 -
-
-
接口定义:
int ResponseProcess::Process(int result, int requestCode, const string& response, const vector<string>& vecCookies, map<string, string>& keyValues) { if (result != 0) { keyValues.insert(make_pair("resultCode", IntToStr(ERROR_REQUEST_FIRST + result))); keyValues.insert(make_pair("failReason", GbkToUtf8("网络传输异常!"))); return 0; } for (vector<string>::const_iterator iter = vecCookies.begin(); iter != vecCookies.end(); ++iter) { const string& str = *iter; size_t pos = str.find("="); if (pos != string::npos) { string name = str.substr(0, pos); string value = str.substr(pos+1); pos = value.find(";"); if (pos != string::npos) value = value.substr(0, pos); if (name == "CASTGC") keyValues.insert(make_pair("tgt", value)); else if (name == "CAS_AUTO_LOGIN") keyValues.insert(make_pair("autoLoginSessionKey", value)); else if (name == "CODEKEY") keyValues.insert(make_pair("codeKey", value)); else if (name == "CAS_PUSHMSG_SESSIONKEY") keyValues.insert(make_pair("pushMsgSessionKey", value)); else keyValues.insert(make_pair(name, value)); } } if (requestCode == REQ_GetQrCode) { if (keyValues.find("codeKey") == keyValues.end()) { keyValues.insert(make_pair("resultCode", IntToStr(ERROR_RESPONSE))); return 0; } keyValues.insert(make_pair("resultCode", "0")); keyValues.insert(make_pair("picData", response)); }else if(requestCode == REQ_CreateWeGameOrder || requestCode == REQ_CreateQQGameOrder || requestCode == REQ_CreateLxOrder || requestCode == REQ_CreateSteamChannelOrder){ json_object* root = json_tokener_parse(response.c_str()); if (is_error(root)) { keyValues["resultCode"] = IntToStr(ERROR_RESPONSE); return 0; } json_object* json = json_object_object_get(root, "code"); if (is_error(json)) { keyValues["resultCode"] = IntToStr(ERROR_RESPONSE); json_object_put(root); return 0; } const char* value = json_object_get_string(json); keyValues["resultCode"] = value; if(atoi(value) == 0){ json_object* data = json_object_object_get(root, "data"); if(data != NULL && !is_error(data)){ json_object_object_foreach(data, key, val) { if(val != NULL && !is_error(val)){ keyValues[key] = json_object_get_string(val); }else{ keyValues[key] = ""; } } } } if (keyValues.find("resultCode") == keyValues.end()) { keyValues["resultCode"] = "0"; } if (keyValues["resultCode"] != "0" && keyValues.find("msg") == keyValues.end()) { json = json_object_object_get(root, "msg"); if (!is_error(json)) { value = json_object_get_string(json); keyValues["resultMsg"] = value; } } json_object_put(root); } else if(requestCode == REQ_FaceVerifyInit || requestCode == REQ_FaceCodeResult || requestCode == REQ_FaceSendAction){ json_object* root = json_tokener_parse(response.c_str()); if (is_error(root)) { keyValues["resultCode"] = IntToStr(ERROR_RESPONSE); return 0; } json_object* json = json_object_object_get(root, "resultCode"); if (is_error(json)) { keyValues["resultCode"] = IntToStr(ERROR_RESPONSE); json_object_put(root); return 0; } const char* value = json_object_get_string(json); keyValues["resultCode"] = value; json_object* data = json_object_object_get(root, "data"); if(data != NULL && !is_error(data)){ json_object_object_foreach(data, key, val) { if(val != NULL && !is_error(val)){ keyValues[key] = json_object_get_string(val); }else{ keyValues[key] = ""; } } } if (keyValues.find("resultCode") == keyValues.end()) { keyValues["resultCode"] = "0"; } if (keyValues["resultCode"] != "0" && keyValues.find("resultMsg") == keyValues.end()) { json = json_object_object_get(root, "resultMsg"); if (!is_error(json)) { value = json_object_get_string(json); keyValues["resultMsg"] = value; } } json_object_put(root); } else { // 由于采用cookie方式自动登录只能支持一个帐号登录,并且会和网页自动登录发生冲突 // 因此除了二维码之外所有的参数改为通过响应包内容直接获取 // 这里为了兼容老的方式仍然保留cookie参数的逻辑, // 因此如果响应包中包含的参数需要覆盖cookie中获取的参数, // 因此这里不能使用map::insert,只能使用map[key]=value方式 json_object* root = json_tokener_parse(response.c_str()); if (is_error(root)) { keyValues["resultCode"] = IntToStr(ERROR_RESPONSE); return 0; } json_object* json = json_object_object_get(root, "return_code"); if (is_error(json)) { keyValues["resultCode"] = IntToStr(ERROR_RESPONSE); json_object_put(root); return 0; } const char* value = json_object_get_string(json); keyValues["resultCode"] = value; json_object* data = json_object_object_get(root, "data"); json_object_object_foreach(data, key, val) { //新增极验解析wangwenhu 20210607 if(strcmp(key, "captchaParams") == 0){ json_object* obj = json_tokener_parse(json_object_get_string(val)); if(obj != NULL && !is_error(obj)){ json_object* gtData = json_object_object_get(obj, "gtData"); if(gtData != NULL && !is_error(gtData)){ json_object_object_foreach(gtData,gkey,value){ keyValues[gkey] = json_object_get_string(value); } } json_object* picUrl = json_object_object_get(obj, "picUrl"); if (picUrl != NULL && !is_error(picUrl)) { keyValues["picUrl"] = json_object_get_string(picUrl); } } }else{ keyValues[key] = json_object_get_string(val); } } if (keyValues.find("resultCode") == keyValues.end()) { keyValues["resultCode"] = "0"; } if (keyValues["resultCode"] != "0" && keyValues.find("failReason") == keyValues.end()) { json = json_object_object_get(root, "return_message"); if (!is_error(json)) { value = json_object_get_string(json); keyValues["failReason"] = value; } } json_object_put(root); } return 0; }
- 这是
ResponseProcess
类的Process
函数的具体实现,用于处理响应数据。以下是函数的主要功能:- 如果
result
不等于 0,表示请求处理失败,将相关错误信息存储在keyValues
中,包括resultCode
和failReason
。resultCode
包含错误代码,而failReason
包含描述失败原因的消息。 - 解析
vecCookies
中的 Cookie 信息,将其中的特定 Cookie 名称和值提取到keyValues
中。这些特定 Cookie 包括:CASTGC
:用于存储tgt
值。CAS_AUTO_LOGIN
:用于存储autoLoginSessionKey
值。CODEKEY
:用于存储codeKey
值。CAS_PUSHMSG_SESSIONKEY
:用于存储pushMsgSessionKey
值。- 其他 Cookie:将它们的名称和值一一存储在
keyValues
中。
- 针对不同的
requestCode
,采用不同的处理逻辑。以下是一些特定请求代码的处理逻辑:- 对于
REQ_GetQrCode
请求,如果response
中没有codeKey
,则将resultCode
设置为错误代码,否则将resultCode
设置为 0,并将picData
存储在keyValues
中。 - 对于一些特定请求,如
REQ_CreateWeGameOrder
、REQ_CreateQQGameOrder
等,将response
解析为 JSON 格式,提取其中的resultCode
和data
。如果resultCode
为 0,还会提取并存储data
中的键值对。 - 对于
REQ_FaceVerifyInit
、REQ_FaceCodeResult
和REQ_FaceSendAction
请求,也会解析response
为 JSON 格式,提取resultCode
和data
,并将其存储在keyValues
中。 - 对于其他请求,将
response
解析为 JSON 格式,提取return_code
和data
,将其存储在keyValues
中。如果resultCode
不为 0,还会提取并存储return_message
作为failReason
。
- 对于
- 根据处理结果,将相应的信息存储在
keyValues
中,然后返回 0 表示处理完成。
- 如果
- 总之,
ResponseProcess
的Process
函数用于根据不同的请求代码和响应数据,将关键信息提取并存储在keyValues
中,以便后续的处理逻辑使用。这种处理响应的方式使代码能够根据请求的不同,以一种通用的方式解析不同格式的响应数据。- 这里处理的响应数据通常是 JSON 格式的数据。在具体的处理过程中,会使用 JSON 解析库(在这里似乎使用了
json-c
库)来解析响应数据,提取其中的信息。根据不同的请求和响应结构,会选择不同的字段进行提取和处理。 - 在代码中,有多个条件分支,针对不同的请求代码(
requestCode
)来解析 JSON 数据,并提取相应的字段。这种设计可以处理多种不同类型的响应,使代码更加通用和灵活。
- 这里处理的响应数据通常是 JSON 格式的数据。在具体的处理过程中,会使用 JSON 解析库(在这里似乎使用了
- 这是
-
-
-
接着,它检查请求代码(
requestCode
)是否在m_mapResponseFunc
中有对应的处理函数。这个映射表将请求代码与响应处理函数关联起来。 -
如果找到了对应的处理函数(
iterFunc != m_mapResponseFunc.end()
),则调用相应的处理函数,将请求代码和处理后的数据(keyValues
)传递给该函数。 -
在处理过程中,根据
isUrl2
的值,设置keyValues
中的"isUrl2"
键。 -
如果存在等待事件
m_waitEvent
,则检查它的状态,如果当前状态不是等待状态(WAIT_OBJECT_0
),则设置事件为有信号状态(SetEvent(m_waitEvent)
)。这可能用于通知等待此事件的其他线程。 -
最后,将处理后的
keyValues
映射到m_mapValList
中,以便后续使用。
-
-
总之,这段代码的主要目的是根据请求代码执行相应的响应处理函数,并将处理后的数据存储在
keyValues
和m_mapValList
中,同时处理事件等待。这是一个典型的网络请求处理逻辑。
6、ProcessThread调用ProcessResponse
函数声明:
unsigned ProcessThread();
unsigned ProcessThread();
是一个函数的声明,它表明这是一个无参数函数(不带任何输入参数)并且返回一个无符号整数 (unsigned
)。函数名为ProcessThread
,但在这个片段中只是函数的声明,没有给出具体的函数实现。- 通常,这样的声明会在某个类的头文件中出现,用于告诉编译器该类中有一个名为
ProcessThread
的成员函数,而具体的函数实现则在类的源文件中提供。在源文件中,你会找到ProcessThread
函数的实际代码,包括函数体内的操作。
函数定义:
unsigned HttpThread::ProcessThread()
{
while (m_running)
{
WaitForSingleObject(m_event, INFINITE);
HttpRequest* request = m_request;
m_request = NULL;
if (request != NULL)
{
string response;
vector<string> vecCookies;
int ret = 0;
bool isUrl2 = false;
static bool isUrlFailed = false;
static string publicKey = "";
static bool isHostBackup3or4 = false;
// 当有host3和host4时候,host1和host2尝试失败则重新试host3和host4
HOST_BACKUP:
int count = 0;
if (!isUrlFailed)
{
// https连接
ret = m_httpClient.SendHttpRequest(request->hostName, request->port,
request->url, request->method, request->postData,
request->timeout, response, vecCookies, m_proxyEnable);
count++;
isUrlFailed = (ret != 0);
}
if (request->requestCode != REQ_SendPushMessageVerifyCheckCode && m_loginClient)
{
m_loginClient->ClearPushMessageVerifyCheckCodeStatus();
}
if (isUrlFailed && request->requestCode == REQ_GetDynamicKey && publicKey.length() == 0)
{
// http,并先获取publickey
int r = GetPublicKey(publicKey, response, vecCookies, m_proxyEnable);
if (r != 0 || publicKey.length() == 0)
{
if (!isHostBackup3or4)
{
// 初始化host3和host4状态
request->hostName = m_hostName3;
request->port = m_hostPort3;
request->hostName2 = m_hostName4;
request->port2 = m_hostPort4;
isUrlFailed = false;
ret = 0;
publicKey = "";
response = "";
m_loginClient->SetHost3AndHost4(m_hostName3, m_hostPort3, m_hostName4, m_hostPort4);
isHostBackup3or4 = true;
goto HOST_BACKUP;
}
// publicKey获取失败
m_state = STATE_IDLE;
m_outUserData = request->userData;
m_loginClient->ProcessResponse(r, request->requestCode, response, vecCookies, isUrl2);
delete request;
continue;
}
else
{
m_outUserData = request->userData;
delete request;
response = "";
vecCookies.clear();
request = m_loginClient->GetDynamicKeyRequest(publicKey);
request->userData = m_outUserData;
}
}
if(count == 0)
{
string url = request->url2.length() > 0 ? request->url2 : request->url;
// 如果url失败,那么都都用url2,认证
ret = m_httpClient.SendHttpRequest(request->hostName2, request->port2,
url, request->method, request->postData,
request->timeout2, response, vecCookies, m_proxyEnable);
isUrl2 = true;
}
if (ret != 0 && !request->hostName2.empty())
{
string url = request->url2.length() > 0? request->url2:request->url;
ret = m_httpClient.SendHttpRequest(request->hostName2, request->port2,
url, request->method, request->postData,
request->timeout2, response, vecCookies, m_proxyEnable);
isUrl2 = true;
}
m_state = STATE_IDLE;
m_outUserData = request->userData;
m_loginClient->ProcessResponse(ret, request->requestCode, response, vecCookies, isUrl2);
delete request;
}
}
return 0;
}
-
这段代码是一个线程处理函数,通常在后台运行,用于处理 HTTP 请求和响应。以下是它的主要功能:
-
在一个循环中等待事件触发:
WaitForSingleObject(m_event, INFINITE)
,当有请求到达时,会触发这个事件。 -
获取请求对象:
HttpRequest* request = m_request;
,从请求队列中获取一个 HTTP 请求对象。 -
处理请求:
-
发送 HTTP 请求:使用
m_httpClient
对象发送 HTTP 请求,包括指定的主机、端口、URL、请求方法、POST 数据等。-
发送HTTP请求函数调用:
ret = m_httpClient.SendHttpRequest(request->hostName, request->port, request->url, request->method, request->postData, request->timeout, response, vecCookies, m_proxyEnable);
-
函数声明:
int SendHttpRequest(const string& hostName, int port, const string& url, const string& method, const string& postData, int timeout, string& response, vector<string>& vecCookies, bool proxyEnable);
- 这是一个用于发送 HTTP 请求的函数,它接受一些参数来定义请求的各个方面。下面是各参数的作用:
hostName
:指定要发送请求的主机名或 IP 地址。port
:指定要连接的端口号。url
:指定请求的 URL 地址。method
:指定 HTTP 请求方法,通常为 “GET” 或 “POST”。postData
:如果使用 “POST” 方法,这里包含请求的实体数据,通常是表单数据或 JSON 数据。timeout
:指定请求的超时时间,即允许服务器响应的最长等待时间。response
:用于接收服务器响应的字符串。vecCookies
:用于接收响应中的 Cookies(如果有的话)。proxyEnable
:一个布尔值,指示是否启用代理。
- 这个函数的作用是根据给定的参数创建一个 HTTP 请求,将其发送到指定的主机和端口,等待服务器响应,并将响应的数据和 Cookies 存储到相应的参数中。这是一个常见的 HTTP 请求发送和响应接收函数,用于与远程服务器进行通信。
- 这是一个用于发送 HTTP 请求的函数,它接受一些参数来定义请求的各个方面。下面是各参数的作用:
-
函数定义:
int HttpClient::SendHttpRequest(const string& hostName, int port, const string& urlPath, const string& method, const string& urlParam, int timeout, string& response, vector<string>& vecCookies, bool proxyEnable) { TRACET(); ResetEvent(); DWORD proxyFlag; if (proxyEnable) proxyFlag = INTERNET_OPEN_TYPE_PRECONFIG; else proxyFlag = INTERNET_OPEN_TYPE_DIRECT; m_hInternet = ::InternetOpenA("Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) ; InfoPath.2; .NET CLR 2.0.50727; MS-RTC LM 8; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET CLR 1.1.4322; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)", proxyFlag, NULL, NULL, INTERNET_FLAG_ASYNC); if (m_hInternet == NULL) { // printf("InternetOpenA wait io pending timeout %d.\n", timeout); TRACEE(L"InternetOpenA wait io pending timeout %d.error = %d,return = -7\n",timeout,GetLastError()); m_step = STEP_NULL; return -7; } ::InternetSetStatusCallbackA(m_hInternet, &HttpClient::InternetStatusCallback); ::InternetSetOptionA(m_hInternet, INTERNET_OPTION_RECEIVE_TIMEOUT, (LPVOID)&timeout, sizeof(timeout)); m_step = STEP_CONN; m_hConnect = ::InternetConnectA(m_hInternet, hostName.c_str(), port, NULL, NULL, INTERNET_SERVICE_HTTP, 0, (DWORD_PTR)this); try { if (m_hConnect == NULL && ::GetLastError() == ERROR_IO_PENDING) { printf("InternetConnect wait io pending.\n"); if (::WaitForSingleObject(m_connEvent, timeout) != 0) { //printf("InternetConnect wait io pending timeout %d.\n", timeout); TRACEE(L"InternetConnect wait io pending timeout %d.error = %d,return = -1\n",timeout,GetLastError()); m_step = STEP_NULL; ::InternetSetStatusCallbackA(m_hInternet, NULL); ::InternetCloseHandle(m_hInternet); return -1; } if (m_step == STEP_CANCEL) { throw FALSE; } } } catch (BOOL ex) { //printf("InternetConnect failed. User Cancel.\n"); TRACEE(L"InternetConnect failed. User Cancel.error = %d,return = -1\n",GetLastError()); m_step = STEP_NULL; ::InternetSetStatusCallbackA(m_hInternet, NULL); ::InternetCloseHandle(m_hInternet); return -1; } if (m_hConnect == NULL) { //printf("InternetConnect failed. error %d.\n", GetLastError()); TRACEE(L"InternetConnect failed.error = %d,return = -2\n",GetLastError()); m_step = STEP_NULL; ::InternetSetStatusCallbackA(m_hInternet, NULL); ::InternetCloseHandle(m_hInternet); return -2; } m_step = STEP_REQ; DWORD dwFlag = INTERNET_FLAG_RELOAD; if (port == INTERNET_DEFAULT_HTTPS_PORT) dwFlag = INTERNET_FLAG_RELOAD | INTERNET_FLAG_SECURE | INTERNET_FLAG_IGNORE_CERT_CN_INVALID | INTERNET_FLAG_IGNORE_CERT_DATE_INVALID; m_hRequest = HttpOpenRequestA(m_hConnect, method.c_str(), urlPath.c_str(), "HTTP/1.1", NULL, NULL, dwFlag, (DWORD_PTR)this); try { if (m_hRequest == NULL && ::GetLastError() == ERROR_IO_PENDING) { printf("HttpOpenRequest wait io pending.\n"); if (::WaitForSingleObject(m_requestEvent, timeout) != 0) { //printf("HttpOpenRequest wait io pending timeout %d.\n", timeout); TRACEE(L"HttpOpenRequest wait io pending timeout %d.error = %d,return = -3\n",timeout,GetLastError()); m_step = STEP_NULL; ::InternetSetStatusCallbackA(m_hConnect, NULL); ::InternetSetStatusCallbackA(m_hInternet, NULL); ::InternetCloseHandle(m_hConnect); ::InternetCloseHandle(m_hInternet); return -3; } if (m_step == STEP_CANCEL) { throw FALSE; } } } catch (BOOL ex) { //printf("HttpOpenRequest failed. User Cancel.\n"); TRACEE(L"HttpOpenRequest failed. User Cancel.error = %d,return = -3\n",GetLastError()); m_step = STEP_NULL; ::InternetSetStatusCallbackA(m_hConnect, NULL); ::InternetSetStatusCallbackA(m_hInternet, NULL); ::InternetCloseHandle(m_hConnect); ::InternetCloseHandle(m_hInternet); return -3; } if (m_hRequest == NULL) { printf("HttpOpenRequest failed. error %d.\n", GetLastError()); m_step = STEP_NULL; ::InternetSetStatusCallbackA(m_hConnect, NULL); ::InternetSetStatusCallbackA(m_hInternet, NULL); ::InternetCloseHandle(m_hConnect); ::InternetCloseHandle(m_hInternet); return -4; } m_step = STEP_SEND; BOOL bRet = ::HttpSendRequest(m_hRequest, NULL, 0, (char*)urlParam.c_str(), (DWORD)urlParam.length()); //printf("HttpSendRequest. code %d.\n", GetLastError()); if(GetLastError() != 0){ TRACEE(L"HttpSendRequest,error = %d\n",GetLastError()); } try { if (::WaitForSingleObject(m_compliteEvent, timeout) != 0) { //printf("HttpSendRequest timeout. error %d.\n", GetLastError()); TRACEE(L"HttpSendRequest timeout.error = %d,return =-5\n",GetLastError()); m_step = STEP_NULL; ::InternetSetStatusCallbackA(m_hRequest, NULL); ::InternetSetStatusCallbackA(m_hConnect, NULL); ::InternetSetStatusCallbackA(m_hInternet, NULL); ::InternetCloseHandle(m_hRequest); ::InternetCloseHandle(m_hConnect); ::InternetCloseHandle(m_hInternet); return -5; } if (m_step == STEP_CANCEL) { throw FALSE; } } catch (BOOL ex) { //printf("HttpSendRequest timeout. User Cancel.\n"); TRACEE(L"HttpSendRequest timeout. User Cancel.error = %d,return =-5\n",GetLastError()); m_step = STEP_NULL; ::InternetSetStatusCallbackA(m_hRequest, NULL); ::InternetSetStatusCallbackA(m_hConnect, NULL); ::InternetSetStatusCallbackA(m_hInternet, NULL); ::InternetCloseHandle(m_hRequest); ::InternetCloseHandle(m_hConnect); ::InternetCloseHandle(m_hInternet); return -5; } DWORD dwStatusCode = 0, dwStatusSize = sizeof(DWORD); BOOL nRet = ::HttpQueryInfoA(m_hRequest, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &dwStatusCode, &dwStatusSize, 0); if (!nRet || dwStatusCode != 200) { //printf("HttpQueryInfo. statecode %d code %d.\n", dwStatusCode, GetLastError()); TRACEE(L"HttpQueryInfo. statecode %d.error = %d,return =-6\n",dwStatusCode,GetLastError()); m_step = STEP_NULL; ::InternetSetStatusCallbackA(m_hRequest, NULL); ::InternetSetStatusCallbackA(m_hConnect, NULL); ::InternetSetStatusCallbackA(m_hInternet, NULL); ::InternetCloseHandle(m_hRequest); ::InternetCloseHandle(m_hConnect); ::InternetCloseHandle(m_hInternet); return -6; } DWORD count = 0; do { char cookies[2048] = {0}; dwStatusSize = 2047; nRet = ::HttpQueryInfoA(m_hRequest, HTTP_QUERY_SET_COOKIE, &cookies, &dwStatusSize, &count); if (nRet) vecCookies.push_back(cookies); if (m_step == STEP_CANCEL) { break; } } while (nRet); while (m_step != STEP_CANCEL) { char readBuffer[4096] = {0}; unsigned long numberOfBytesRead = 0; bRet = InternetReadFile(m_hRequest, readBuffer, sizeof(readBuffer)-1, &numberOfBytesRead); if (!bRet) { if (::GetLastError() == ERROR_IO_PENDING) { if (::WaitForSingleObject(m_compliteEvent, timeout) != 0) { printf("InternetReadFile wait io pending timeout. %d.\n", timeout); response = ""; break; } } else { printf("InternetReadFile failed. error %d.\n", GetLastError()); response = ""; break; } } if (numberOfBytesRead == 0) { break; } response += string(readBuffer, numberOfBytesRead); } m_step = STEP_NULL; ::InternetSetStatusCallbackA(m_hRequest, NULL); ::InternetSetStatusCallbackA(m_hConnect, NULL); ::InternetSetStatusCallbackA(m_hInternet, NULL); ::InternetCloseHandle(m_hRequest); ::InternetCloseHandle(m_hConnect); ::InternetCloseHandle(m_hInternet); //::HttpEndRequestA(m_hRequest,NULL,NULL,NULL); return 0; }
- 这段代码是一个 HTTP 请求的处理过程。以下是它的主要步骤:
- 使用
::InternetOpenA
函数打开一个 Internet 连接,根据proxyEnable
参数来决定是否使用代理。 - 设置回调函数
HttpClient::InternetStatusCallback
以处理连接状态变化。 - 使用
::InternetConnectA
函数连接到指定的主机和端口。 - 使用
::HttpOpenRequestA
函数打开一个 HTTP 请求,根据给定的 HTTP 方法和 URL。 - 使用
::HttpSendRequest
函数发送请求,包括请求的实体数据(如果有的话)。 - 等待服务器响应的完成,使用
::WaitForSingleObject
函数。 - 如果状态码不是 200(OK),则返回错误。
- 获取响应中的 Cookies,并存储到
vecCookies
中。 - 从服务器响应中读取数据,将其存储在
response
变量中。 - 最后,关闭所有相关的 Internet 句柄。
- 使用
- 这个函数完成了一个完整的 HTTP 请求过程,包括建立连接、发送请求、接收响应和关闭连接。在请求过程中,使用了一些事件(如
m_connEvent
、m_requestEvent
和m_compliteEvent
)来等待异步操作完成。
- 这段代码是一个 HTTP 请求的处理过程。以下是它的主要步骤:
-
-
检查请求是否成功:通过
ret
变量来判断请求是否成功,通常 0 表示成功,非 0 表示失败。 -
处理请求的响应:如果请求成功,将得到响应数据,同时获取到的 Cookie 信息也保存在
vecCookies
中。 -
通过
m_loginClient->ProcessResponse
处理响应:将请求的结果、请求代码和响应数据传递给m_loginClient
对象来处理。
-
-
在一些特殊情况下,会进行一些额外的操作,例如获取公钥、切换主机地址、处理备用主机等。这些操作都是为了增加系统的稳定性和容错性。
-
-
总之,这段代码实现了一个后台线程,负责发送 HTTP 请求并处理响应,同时具备一些容错和切换逻辑以确保系统的可靠性。
if(count == 0)
{
string url = request->url2.length() > 0 ? request->url2 : request->url;
// 如果url失败,那么都都用url2,认证
ret = m_httpClient.SendHttpRequest(request->hostName2, request->port2,
url, request->method, request->postData,
request->timeout2, response, vecCookies, m_proxyEnable);
isUrl2 = true;
}
if (ret != 0 && !request->hostName2.empty())
{
string url = request->url2.length() > 0? request->url2:request->url;
ret = m_httpClient.SendHttpRequest(request->hostName2, request->port2,
url, request->method, request->postData,
request->timeout2, response, vecCookies, m_proxyEnable);
isUrl2 = true;
}
m_state = STATE_IDLE;
m_outUserData = request->userData;
m_loginClient->ProcessResponse(ret, request->requestCode, response, vecCookies, isUrl2);
delete request;
- 这段代码看起来是一个处理HTTP请求的逻辑。它首先检查一个名为
count
的变量是否等于 0,然后根据条件执行HTTP请求,并根据请求的结果设置一些标志和参数。让我一步一步解释:count
是一个变量,它在前面的代码中定义,但这段代码中没有给出其定义和初始化。这里检查count
是否等于 0,如果等于 0,表示某种情况下的失败。- 如果
count
等于 0,表示前面的 HTTP 请求失败,代码接着处理以下步骤:- 从
request
对象中获取url
或url2
,这取决于它们是否非空(length() > 0
),然后将其存储在名为url
的字符串中。 - 使用
m_httpClient
对象的SendHttpRequest
方法,向指定的hostName2
和port2
发送 HTTP 请求,使用刚刚获取的url
,request->method
、request->postData
等参数。 - 将请求的结果(响应数据)存储在
response
变量中,并将响应中的 cookies 存储在vecCookies
中。 - 将
isUrl2
设置为true
,表示使用了备用的url2
。
- 从
- 接下来,代码检查
ret
是否不等于 0 并且request->hostName2
不为空。如果条件成立,它再次执行 HTTP 请求的相同步骤,但这次使用的 URL 依然是url2
。 - 然后,代码设置了
m_state
为STATE_IDLE
,将m_outUserData
设置为request->userData
,并调用m_loginClient
对象的ProcessResponse
方法来处理 HTTP 请求的结果。传递给ProcessResponse
的参数包括ret
(HTTP 请求的返回码),request->requestCode
(请求的代码),response
(响应数据),vecCookies
(响应中的 cookies),以及isUrl2
表示是否使用备用 URL。 - 最后,代码删除了
request
对象,以释放相应的资源。
- 总的来说,这段代码用于处理 HTTP 请求的情况,当首次请求失败(
count == 0
)时,会尝试备用 URL,然后根据请求结果和其他参数来处理请求的响应数据。
7、ThreadEntry调用ProcessThread
函数声明:
static unsigned _stdcall ThreadEntry(void* param);
- 这是一个静态成员函数
_stdcall ThreadEntry
,通常用于创建新线程的入口点。下面是一些重要信息:static
: 这个函数是静态的,所以它与类的实例无关,可以通过类名调用它,而不需要类的实例。unsigned
: 这是函数的返回类型,表示函数将返回一个unsigned
整数。_stdcall
: 这是函数调用约定的一种,它指定了函数调用时的堆栈清理方式。_stdcall
调用约定在函数返回后由被调用的函数来清理堆栈。这是 Windows 平台上的一种常见调用约定。ThreadEntry
: 这是函数的名称,它将在新线程中执行的入口点函数。新线程在启动时将执行此函数。void* param
: 这是函数的参数,通常用于传递给新线程的数据或上下文信息。void*
表示参数是一个指针,因此可以传递任何类型的数据。
- 在 Windows 平台上,创建一个新线程通常需要指定一个入口点函数,这个函数会在新线程中执行。
_stdcall
调用约定和unsigned
返回类型是在 Windows 环境中的线程函数的常见组合。函数接受一个void*
参数,允许你在新线程中传递数据。 - 通常,这个函数会执行一些特定的任务,然后返回一个整数值作为线程的退出码。这个退出码可以被父线程或其他线程用来获取有关线程执行的信息。
函数定义:
unsigned _stdcall HttpThread::ThreadEntry(void* param)
{
HttpThread* pThis = (HttpThread*)param;
return pThis->ProcessThread();
}
- 这是
HttpThread
类中的静态成员函数ThreadEntry
的实现。它是用于在新线程中执行的入口点函数。以下是关于这段代码的解释:unsigned _stdcall
: 这部分指定了函数的返回类型和调用约定。_stdcall
调用约定用于 Windows 环境,它表示在函数返回时由被调用的函数来清理堆栈。unsigned
表示该函数将返回一个无符号整数。HttpThread::ThreadEntry(void* param)
: 这是函数的声明,它接受一个void*
参数,通常用于传递数据给新线程。在这里,param
参数会传递给新线程,作为指向HttpThread
对象的指针。HttpThread* pThis = (HttpThread*)param;
: 这一行将param
转换为HttpThread
类型的指针pThis
。这是因为ThreadEntry
函数是静态的,它没有访问实例变量,所以需要将传递的参数转换为HttpThread
类型的指针,以便在函数内部使用。- 在C++中,非静态成员函数通常依赖于类的实例(对象)来访问和操作类的成员变量和方法。静态成员函数则不依赖于类的实例,它们可以直接被类名调用,因此无法访问非静态成员或实例变量。这是因为静态成员函数不与特定的对象实例相关联,它们更像是全局函数,只能访问静态成员和局部变量。
- 在你的代码中,
ThreadEntry
是一个静态成员函数,它用作线程的入口点。线程在启动时需要一个入口点函数,它不能依赖于类的实例,因此必须是静态的。因为它是静态的,所以无法直接访问HttpThread
类的实例变量或成员函数,除非通过参数传递指向实例的指针(param
参数)。- 由于静态成员函数不依赖于类的实例,所以它们无法直接访问或操作类的实例变量或非静态成员函数。为了在静态函数内部访问类的实例相关内容,你可以通过将实例的指针作为参数传递给静态函数来实现。
- 在你的代码中,
ThreadEntry
是一个静态成员函数,它是线程的入口点。当你创建一个线程并指定入口点函数时,通常可以传递一个参数,这个参数是一个指向类实例的指针,这个指针会作为param
参数传递给ThreadEntry
函数。 - 这样做的目的是,通过这个参数,
ThreadEntry
函数可以获得对类实例的访问权限,从而可以在静态函数内部访问实例变量和调用实例方法。这是一种在静态函数中访问实例相关内容的常见技巧。这个参数通常被称为上下文参数,它允许将上下文信息传递给静态函数,以便在函数内部使用。
- 通过将
param
参数转换为HttpThread
类型的指针,你可以在ThreadEntry
函数内部访问HttpThread
对象的成员和方法。这种方式允许你在静态函数中访问实例相关的内容。当线程创建时,通常会将线程入口函数的参数传递给新线程,以便在新线程内部使用。这种方法允许你在多线程环境中执行对象的方法,即使入口点函数是静态的。
return pThis->ProcessThread();
: 这一行调用pThis
指向的HttpThread
对象的ProcessThread
方法,执行线程的实际工作。函数返回ProcessThread
的返回值,这将作为新线程的退出码。
- 总之,
ThreadEntry
函数是用于创建新线程的入口点,它接受一个void*
参数,将其转换为HttpThread
对象的指针,然后调用ProcessThread
方法执行线程的任务。线程完成后,将返回ProcessThread
的返回值。
HttpThread::HttpThread(LoginClient* loginClient)
: m_loginClient(loginClient)
, m_state(STATE_IDLE)
, m_running(true)
, m_request(NULL)
, m_proxyEnable(true)
, m_inUserData(NULL)
, m_outUserData(NULL)
, m_hostPort3(0)
, m_hostPort4(0)
{
m_event = ::CreateEvent(NULL, FALSE, FALSE, NULL);
m_thread = (HANDLE)::_beginthreadex(NULL, 0, &HttpThread::ThreadEntry, this, 0, NULL);
}
- 这段代码是一个类
HttpThread
的构造函数,用于初始化HttpThread
类的实例。以下是它的主要功能:- 初始化
m_loginClient
成员,这是一个指向LoginClient
类的指针,表示将LoginClient
对象与HttpThread
关联起来。 - 初始化
m_state
为STATE_IDLE
,m_running
为true
,m_request
为NULL
,m_proxyEnable
为true
,以及其他成员变量的初始值。 - 创建一个事件对象
m_event
,该事件对象用于线程同步和控制。 - 使用
_beginthreadex
函数创建一个新的线程,该线程将执行HttpThread::ThreadEntry
函数,传递this
指针作为参数,从而允许在新线程中执行HttpThread
的成员函数。
- 初始化
- 这段代码的目的是创建一个
HttpThread
实例,该实例用于处理 HTTP 请求。在构造函数中,它初始化了线程、事件、以及与LoginClient
对象的关联。随后,该线程可以等待请求,并在请求到达时执行相应的操作。
2、SdoBase_SsoLogin4举例使用
1、SdoBase_SsoLogin4接口调用
函数声明:
int SDOAPI SdoBase_SsoLogin4(SdoBaseHandle* handle,int appId); // 为游戏盒子新增,增加appId,用于区分商城与其他来源
-
这是一个函数声明,它看起来是一个用于进行单点登录 (SSO) 的接口函数。该函数的声明包括以下部分:
-
int
: 这表示函数的返回值类型是整数,通常用于指示函数执行的结果或状态。 -
SDOAPI
: 这可能是一个宏或宏函数,用于定义函数的可见性和导出规则,具体实现可能因代码库而异。 -
SdoBase_SsoLogin4
: 这是函数的名称。 -
(SdoBaseHandle* handle, int appId)
: 这是函数的参数列表,函数接受两个参数:
SdoBaseHandle* handle
: 一个指向SdoBaseHandle
类型的指针。int appId
: 一个整数参数,表示应用程序的 ID。
-
-
函数声明表明该函数将返回一个整数值,可能用于指示登录操作的结果或状态。通常,函数的具体实现将接受指向应用程序句柄的指针和应用程序的 ID,以执行单点登录操作并返回适当的结果。这个函数的实际实现将取决于代码库或程序中的上下文和要求。
函数定义:
extern "C" int SDOAPI SdoBase_SsoLogin4(SdoBaseHandle* handle,int appId)
{
LoginClient* app = (LoginClient*)handle;
return app->SsoLogin(NULL,NULL,appId);
}
- 这是一个 C++ 函数的实现,该函数使用了
extern "C"
来指示编译器按照 C 语言的规则进行符号导出,以便在 C 语言或其他语言中调用。函数实现的细节如下:extern "C"
: 这是一个编译指示,告诉编译器要按照 C 语言的规则导出函数,这通常用于确保函数可以从纯 C 语言的上下文中调用。- 使用
extern "C"
主要是为了确保函数可以按照 C 语言的调用约定进行导出和链接。这对于以下情况非常有用:- 兼容性: 当你希望在 C++ 代码中定义的函数可以被其他语言(通常是 C 语言)调用时,
extern "C"
可以确保这些函数的命名和参数传递方式与 C 语言的规则相匹配,从而实现兼容性。 - 动态链接库(DLL)/共享库(SO)的导出: 在跨编程语言的动态链接库或共享库中,使用
extern "C"
可以确保库的函数和变量可以被其他编程语言的程序正确链接和调用。 - 函数名修饰: 在 C++ 中,函数名通常会根据其参数类型进行修饰,这就导致了所谓的 “name mangling”。使用
extern "C"
可以避免这种修饰,保持函数名的原始形式。 - C 语言接口的实现: 当你需要为 C 语言的接口实现 C++ 函数时,
extern "C"
可以确保这些函数的声明和定义与 C 语言的接口一致,使得 C 语言程序可以调用这些函数。
- 兼容性: 当你希望在 C++ 代码中定义的函数可以被其他语言(通常是 C 语言)调用时,
- 总之,
extern "C"
主要用于确保 C++ 代码可以与其他编程语言或标准 C 语言保持兼容,而不会受到 C++ 的特性(如函数重载和名称修饰)的影响。这对于创建共享库、跨语言编程以及提供标准 C 接口的情况非常重要。
- 使用
int SDOAPI SdoBase_SsoLogin4(SdoBaseHandle* handle, int appId)
: 这是函数的定义,它与之前的函数声明相匹配。函数接受两个参数:SdoBaseHandle* handle
: 一个指向SdoBaseHandle
类型的指针,通常表示一个句柄或上下文。int appId
: 一个整数参数,表示应用程序的 ID。
- 函数体: 函数体内部的实现如下:
LoginClient* app = (LoginClient*)handle;
: 这行代码将传入的SdoBaseHandle
指针强制转换为LoginClient*
类型的指针,这可能是基于某些上下文信息的。return app->SsoLogin(NULL,NULL,appId);
: 该行代码调用了LoginClient
类的SsoLogin
函数,传递了appId
作为参数,并返回该函数的结果。这里的SsoLogin
函数似乎用于执行单点登录操作。
- 此函数的目的似乎是充当一个接口,将
SdoBaseHandle
类型的句柄和应用程序 ID 传递给LoginClient
类中的SsoLogin
函数,并返回其结果。这是一种常见的方法,用于在不同的代码库之间共享功能或实现跨语言接口。
2、SsoLogin接口调用
函数声明:
int SsoLogin(const char* tgt, const char *scene,int appId);
函数定义:
- 这看起来是一个名为
SsoLogin
的函数,它接受三个参数:const char* tgt
:这是一个指向 C 风格字符串的指针,通常用于传递目标 TGT(Ticket Granting Ticket)。TGT 是一种用于身份验证的票据。const char* scene
:同样是一个指向 C 风格字符串的指针,通常用于指定身份验证场景或用途。int appId
:这是一个整数参数,通常用于标识应用程序的唯一标识符或 ID。
- 函数的返回类型是
int
,这意味着该函数将返回一个整数值。这个整数值通常用于表示函数的执行结果或状态,通常情况下,返回值为 0 表示成功,而其他非零值则表示不同的错误代码或状态。 - 该函数的目的和功能可能是进行用户身份验证或登录,根据传入的 TGT、场景和应用程序 ID 进行相关的处理,并根据处理结果返回相应的状态码。
函数定义:
int LoginClient::SsoLogin(const char* tgt, const char *scene,int appId)
{
m_requestProcess.SetReqParams(&m_mapReqParams);
m_mapReqParams.clear();
HttpRequest* request = m_requestProcess.GetSsoLoginRequest(tgt, scene,appId);
if (request == NULL)
{
return ERROR_FORAT_URL;
}
if (m_httpThread->ProcessRequest(request) != 0)
{
delete request;
return ERROR_PROCESSING;
}
return 0;
}
-
LoginClient::SsoLogin
函数的实现如下:-
首先,它调用了
m_requestProcess.SetReqParams(&m_mapReqParams)
,其中SetReqParams
函数用于设置请求参数。在这之前,它清空了m_mapReqParams
容器。-
函数声明:
void SetReqParams(map<string, string>* mapReqParams);
SetReqParams
函数是用于设置请求参数的函数,它接受一个map<string, string>*
类型的参数mapReqParams
,表示一个字符串键值对的映射。这个函数的目的是将请求所需的参数填充到mapReqParams
中,以便后续的 HTTP 请求能够使用这些参数。- 具体来说,该函数可能会设置一些键值对,这些键值对包括请求的一些参数,如用户名、密码、票据等。这样,当构建 HTTP 请求时,可以从
mapReqParams
中获取这些参数的值,将它们添加到请求的 URL、头部或请求体中,以完成特定的登录或认证请求。 - 这种设计模式可以将请求参数的管理和构建与实际的 HTTP 请求逻辑分离,使代码更加模块化和可维护。
- 这类似于“策略模式”或“构建者模式”的一种结合使用。在这里,
SetReqParams
函数充当了一个构建者(Builder)的角色,它负责构建请求参数的映射。同时,LoginClient
类使用这些构建好的参数来创建实际的 HTTP 请求,这部分逻辑类似于策略模式,其中不同的请求可能需要不同的参数。 - 总的来说,这种模式允许动态构建请求参数并将其与实际的 HTTP 请求逻辑分开,提高了代码的可维护性和扩展性。虽然不完全符合传统的设计模式定义,但结合了多个概念来满足实际需求。这种灵活性和可维护性的设计方法在软件工程中非常常见。
- 这类似于“策略模式”或“构建者模式”的一种结合使用。在这里,
-
函数定义:
void RequestProcess::SetReqParams( map<string, string>* mapReqParams ) { m_mapReqParams.clear(); m_mapReqParams = *mapReqParams; }
-
SetReqParams
函数是RequestProcess
类中的一个方法,它接受一个map<string, string>*
类型的参数mapReqParams
,并将该参数中的键值对映射赋值给类内部的m_mapReqParams
成员变量。这个函数的作用是将外部传递的请求参数映射复制到类的内部,以便后续的请求构建过程中使用这些参数。 -
在这里,
m_mapReqParams
可能是RequestProcess
类内部用于存储请求参数的成员变量,通过将外部传递的参数赋值给它,可以在类内的其他方法中使用这些参数来构建请求。 -
这种设计模式类似于“构建者模式”,其中参数的构建和赋值过程被封装在一个单独的方法中,使得类的使用者可以方便地设置请求参数,同时隐藏了内部的实现细节。
-
-
接下来,它调用
m_requestProcess.GetSsoLoginRequest(tgt, scene, appId)
获取一个用于单点登录的 HTTP 请求对象request
。这个请求可能包含了传递给服务器的信息,如tgt
(Ticket Granting Ticket)、scene
(场景)和appId
(应用程序 ID)。-
函数声明:
HttpRequest* GetSsoLoginRequest(const char* tgt, const char *scene,int appId); // 为游戏盒子新增,增加appId,用于区分商城与其他来源
-
GetSsoLoginRequest
函数是一个用于创建 SSO 登录请求的方法,它接受三个参数:tgt
、scene
和appId
。这个函数的主要作用是根据传入的参数构建一个 SSO 登录请求,返回一个HttpRequest
对象,该对象包含了构建好的请求信息,如请求的 URL、请求方法、请求数据等。 -
根据注释中的说明,
appId
参数用于区分请求的来源,可能在不同场景下会有不同的处理逻辑,这样可以根据不同的appId
值来执行相应的操作。 -
这个函数的设计是一种工厂方法模式,它将对象的创建过程封装在内部,返回一个创建好的对象,使调用者可以方便地获取所需的请求对象,而不必了解创建的具体细节。这有助于提高代码的可维护性和可扩展性。
-
工厂模式是一种创建型设计模式,它提供了一种创建对象的接口,但具体的对象创建过程由子类或实现类来决定。工厂模式将对象的实例化过程封装起来,从而使客户端代码不必了解对象的具体创建方式。
- 以下是一个简单的工厂模式的示例,假设我们有一个形状(Shape)类和它的子类,例如圆形(Circle)和矩形(Rectangle),我们可以使用工厂模式创建这些形状:
#include <iostream> // 抽象形状类 class Shape { public: virtual void draw() = 0; }; // 具体形状 - 圆形 class Circle : public Shape { public: void draw() override { std::cout << "Draw a Circle" << std::endl; } }; // 具体形状 - 矩形 class Rectangle : public Shape { public: void draw() override { std::cout << "Draw a Rectangle" << std::endl; } }; // 形状工厂 class ShapeFactory { public: // 创建形状的工厂方法 Shape* createShape(const std::string& shapeType) { if (shapeType == "Circle") { return new Circle(); } else if (shapeType == "Rectangle") { return new Rectangle(); } else { return nullptr; // 返回空指针表示创建失败 } } }; int main() { ShapeFactory factory; // 使用工厂创建形状对象 Shape* circle = factory.createShape("Circle"); Shape* rectangle = factory.createShape("Rectangle"); // 调用各个形状的 draw 方法 if (circle) { circle->draw(); delete circle; } if (rectangle) { rectangle->draw(); delete rectangle; } return 0; }
- 在上面的示例中,
ShapeFactory
是工厂类,负责根据客户端的需求创建不同的形状对象。客户端通过调用工厂方法createShape
来获取所需的形状对象,而不需要直接实例化具体的形状类。这种方式使代码更加灵活,客户端可以根据需要创建不同的对象,而不必关心对象的具体创建细节。
-
-
-
函数定义:
HttpRequest* RequestProcess::GetSsoLoginRequest(const char* tgt, const char *scene,int appId) { HttpRequest* request = new HttpRequest; request->requestCode = REQ_SsoLogin; string ticket = m_tgt;if(NULL != tgt) ticket = tgt; if(scene==NULL) { request->url = string("authen/ssoLogin.json?tgt=") + ticket + "&guid=" + m_guid + "&scene=" + ""; } else { request->url = string("authen/ssoLogin.json?tgt=") + ticket + "&guid=" + m_guid + "&scene=" + scene; } SetParamToUrl(request->url, &m_mapReqParams); SetCommonParam(request,appId); return request; }
-
在这个示例中,
RequestProcess
类包含了一个工厂方法GetSsoLoginRequest
,用于创建HttpRequest
对象,该对象用于执行 SSO 登录请求。这是一个工厂方法,因为它封装了对象的创建细节,根据传递的参数来构造不同的请求对象。具体解释如下:
-
GetSsoLoginRequest
方法接受三个参数:tgt
(凭证)、scene
(场景)和appId
(应用程序标识)。 -
该方法首先创建一个新的
HttpRequest
对象,然后设置其requestCode
为REQ_SsoLogin
,表示这是一个 SSO 登录请求。 -
然后,根据传递的参数构造请求的 URL。如果
tgt
不为NULL
,则使用传递的tgt
,否则使用m_tgt
成员变量。scene
和appId
也被添加到 URL 中。 -
SetParamToUrl
和SetCommonParam
方法用于设置其他请求参数和通用参数,这些参数将影响请求的行为。-
函数声明:
void SetParamToUrl(string& url, map<string, string>* mapReqParams);
-
SetParamToUrl
方法用于将请求参数添加到 URL 中。它接受两参数:url
:一个字符串引用,表示要构建的URL。mapReqParams
:一个指向字符串键值对的映射(map
)的指针,表示要添加到URL的请求参数。
-
该方法的主要目的是将
mapReqParams
中的键值对参数添加到url
中,以便构造一个完整的URL,其中包含了请求所需的参数信息。这可以用于将客户端请求的数据编码到URL中,以便服务器能够识别和处理请求。- 举个例子,如果
url
的初始值为"https://example.com/api?"
,而mapReqParams
包含以下键值对:
{ "param1": "value1", "param2": "value2", "param3": "value3" }
- 调用
SetParamToUrl(url, mapReqParams)
后,url
的值将变为:
"https://example.com/api?param1=value1¶m2=value2¶m3=value3"
- 这个方法对于构建包含查询参数的URL非常有用,以便向服务器发送请求时能够传递必要的参数信息。
- 举个例子,如果
-
-
函数定义:
void RequestProcess::SetParamToUrl( string& url, map<string, string>* mapReqParams ) { if (mapReqParams == NULL) return; for(map<string, string>::iterator it = mapReqParams->begin(); it != mapReqParams->end(); ++it) { if( it->first.length() <= 0 || it->second.length() <= 0 ) { continue; } if (url.length() > 0 && url[url.length() - 1] != '?') url += "&"; url += it->first + "=" + it->second; } }
-
SetParamToUrl
方法的实现非常简单,它遍历mapReqParams
中的每个键值对,并将它们添加到url
中以构建完整的 URL。方法的主要步骤如下:- 检查
mapReqParams
是否为NULL
,如果是,直接返回,不进行任何操作。 - 使用
for
循环遍历mapReqParams
中的每个键值对。 - 对于每个键值对,首先检查键和值是否都非空(长度大于0)。如果键或值为空,就跳过这个键值对。
- 如果
url
的长度大于0,并且不是以问号?
结尾,就在url
后面添加&
,以便将多个参数连接在一起。 - 然后,将当前键值对的键和值连接成
"key=value"
的形式,添加到url
中。
- 检查
-
这个方法的目的是将参数添加到 URL 中,以便构建一个包含请求参数的完整 URL,该 URL 可以用于发送 HTTP 请求,向服务器传递必要的参数信息。
- 以下是一个简单的HTTP请求示例,使用C++的CURL库执行GET请求:
#include <iostream> #include <curl/curl.h> // 回调函数,用于处理HTTP响应数据 size_t WriteCallback(void* contents, size_t size, size_t nmemb, void* userptr) { size_t totalSize = size * nmemb; std::string* response = static_cast<std::string*>(userptr); response->append(static_cast<char*>(contents), totalSize); return totalSize; } int main() { CURL* curl; CURLcode res; // 初始化CURL库 curl = curl_easy_init(); if (curl) { std::string response; // 设置要访问的URL const char* url = "https://example.com/api/data"; // 设置CURL选项 curl_easy_setopt(curl, CURLOPT_URL, url); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); // 执行HTTP GET请求 res = curl_easy_perform(curl); if (res == CURLE_OK) { // 请求成功,打印响应数据 std::cout << "Response Data: " << response << std::endl; } else { // 请求失败,打印错误信息 std::cerr << "Request failed: " << curl_easy_strerror(res) << std::endl; } // 清理CURL资源 curl_easy_cleanup(curl); } else { std::cerr << "CURL initialization failed." << std::endl; } return 0; }
- 这个示例使用了CURL库来执行一个简单的GET请求,并将响应数据存储在一个字符串中。你可以根据你的需求修改URL和处理响应的方式。确保你的项目中包含了CURL库,并适当链接到CURL库。
-
-
函数声明:
void SetCommonParam(HttpRequest* request, int appId,bool isGet = true); // 为游戏盒子新增,增加appId,用于区分商城与其他来源
- 这是一个函数,用于设置HTTP请求的通用参数,包括appId。下面是该函数的示例实现:
void RequestProcess::SetCommonParam(HttpRequest* request, int appId, bool isGet) { // 这里假设请求的方法是GET,如果需要使用其他HTTP方法,可以根据需要进行修改 if (isGet) { // GET请求需要在URL中添加参数,这里假设参数名为"appId",你可以根据实际情况更改参数名 // 示例URL:https://example.com/api/data?appId=123 if (!request->url.empty()) { request->url += "&"; } else { request->url = "?"; } request->url += "appId=" + std::to_string(appId); } else { // 如果是其他HTTP方法(如POST),可以设置请求体中的参数 // 这取决于API的要求,你需要将"appId"添加到请求体中 // 示例请求体数据:{"appId": 123, "otherParam": "value"} // 注意:需要根据API的要求将数据序列化为JSON或其他适当的格式 // 这里仅提供一个示例,实际实现取决于API的要求和使用的HTTP库 // 你需要使用合适的HTTP库来构建POST请求 } }
-
函数定义:
void RequestProcess::SetCommonParam(HttpRequest* request,int appId, bool isGet) { request->hostName = m_hostName; request->port = m_port; request->hostName2 = m_hostName2; request->port2 = m_port2; request->timeout = m_timeout; request->timeout2 = m_timeout2; string *strurl; if (isGet) { request->method = "GET"; strurl = &request->url; } else { request->method = "POST"; strurl = &request->postData; } if (m_deviceId.size() == 0) { m_deviceId = GetClientSign2(); } if(m_macId.size() == 0){ char szTemp[128] = {0}; int nTempSize = 128; CComputerInfo::GetMacAddress(szTemp, nTempSize); m_macId=szTemp; } char buff[1024]; sprintf(buff, "&authenSource=1&appId=%d&areaId=%d&appIdSite=%d&locale=%s&productId=%d&frameType=1&endpointOS=1&version=21&customSecurityLevel=%d&deviceId=%s&thirdLoginExtern=%s&macId=%s", appId, m_areaid, appId, m_locale!=2?"zh_CN":"en_US", m_productId, m_customSecurityLevel,m_deviceId.c_str(),LoginClient::getThirdLoginExtern().c_str(),m_macId.c_str()); *strurl += buff; if (!m_productVersion.empty()) { *strurl += "&productVersion=" + UrlEncoder::encode(m_productVersion.c_str()); } if (m_tag != -1) { sprintf(buff, "&tag=%d", m_tag); *strurl += buff; } }
-
这个
SetCommonParam
函数的目的是为HTTP请求设置一些通用参数,包括请求的方法、主机名、端口、超时时间、以及一些其他参数。根据isGet
参数,它会设置HTTP请求的方法为GET或POST,并在URL或请求体中添加特定的参数。这个函数会执行以下操作:
- 设置请求的方法,如果是GET请求,则设置为"GET",如果是其他HTTP方法,设置为"POST"。
- 设置请求的主机名和端口,这通常用于指定要连接的服务器地址和端口号。
- 设置请求的超时时间,这是等待服务器响应的最大时间。
- 构建URL或POST请求体数据,包括一系列参数,如
appId
、areaId
、locale
、productId
、frameType
、endpointOS
、version
、customSecurityLevel
、deviceId
、thirdLoginExtern
、macId
等。 - 如果
productVersion
不为空,将其编码后添加到URL中。 - 如果
tag
不等于-1,将其作为参数添加到URL中。
-
这个函数的目的是为每个HTTP请求设置一些共享的参数,以便在发出请求时能够使用这些通用信息。根据请求的类型,这些参数可能会在URL中或POST请求体中使用,这取决于HTTP请求的具体要求。这种方式可以减少在每个HTTP请求中重复设置相同的参数,提高代码的复用性和可维护性。
- 下面是一个简单的示例,展示如何使用
SetCommonParam
函数来为一个HTTP GET请求设置通用参数:
#include <iostream> class HttpRequest { public: std::string method; std::string hostName; int port; std::string url; int timeout; }; class RequestProcess { public: std::string m_hostName; int m_port; int m_timeout; void SetCommonParam(HttpRequest* request, int appId, bool isGet) { request->hostName = m_hostName; request->port = m_port; request->timeout = m_timeout; if (isGet) { request->method = "GET"; request->url = "/api/resource"; } else { request->method = "POST"; request->url = "/api/resource"; } // Add common parameters char buff[1024]; sprintf(buff, "&appId=%d&locale=en_US&frameType=1&version=21&customSecurityLevel=2&deviceId=12345&macId=ABCDE", appId); request->url += buff; if (isGet) { std::cout << "GET Request:" << std::endl; std::cout << "Method: " << request->method << std::endl; std::cout << "Host: " << request->hostName << ":" << request->port << std::endl; std::cout << "URL: " << request->url << std::endl; std::cout << "Timeout: " << request->timeout << " ms" << std::endl; } else { std::cout << "POST Request:" << std::endl; std::cout << "Method: " << request->method << std::endl; std::cout << "Host: " << request->hostName << ":" << request->port << std::endl; std::cout << "URL: " << request->url << std::endl; std::cout << "Timeout: " << request->timeout << " ms" << std::endl; } } }; int main() { RequestProcess requestProcess; requestProcess.m_hostName = "example.com"; requestProcess.m_port = 80; requestProcess.m_timeout = 10000; HttpRequest getRequest; requestProcess.SetCommonParam(&getRequest, 12345, true); HttpRequest postRequest; requestProcess.SetCommonParam(&postRequest, 54321, false); return 0; }
-
在这个示例中,
RequestProcess
类的SetCommonParam
方法用于为GET和POST请求设置通用参数,如主机名、端口、超时时间和一些其他参数。然后,通过调用这个方法,分别为GET和POST请求创建了两个HttpRequest
对象,每个对象包含了相应的通用参数。这个示例展示了如何使用通用参数来构建不同类型的HTTP请求。GET Request: Method: GET Host: example.com:80 URL: /api/resource&appId=12345&locale=en_US&frameType=1&version=21&customSecurityLevel=2&deviceId=12345&macId=ABCDE Timeout: 10000 ms POST Request: Method: POST Host: example.com:80 URL: /api/resource&appId=54321&locale=en_US&frameType=1&version=21&customSecurityLevel=2&deviceId=12345&macId=ABCDE Timeout: 10000 ms
- 这个方法生成一个用于SsoLogin请求的
HttpRequest
对象,并设置了特定的URL和参数。下面是一个完整的SsoLogin请求的示例:
GET Request: Method: GET Host: example.com URL: authen/ssoLogin.json?tgt=YOUR_TICKET_VALUE&guid=YOUR_GUID_VALUE&scene=YOUR_SCENE_VALUE&authenSource=1&appId=YOUR_APP_ID_VALUE&areaId=YOUR_AREA_ID_VALUE&appIdSite=YOUR_APP_ID_VALUE&locale=en_US&productId=YOUR_PRODUCT_ID_VALUE&frameType=1&endpointOS=1&version=21&customSecurityLevel=YOUR_CUSTOM_SECURITY_LEVEL&deviceId=YOUR_DEVICE_ID&thirdLoginExtern=YOUR_THIRD_LOGIN_EXTERN&macId=YOUR_MAC_ID&productVersion=YOUR_PRODUCT_VERSION&tag=YOUR_TAG_VALUE Timeout: 10000 ms
-
请注意,其中的
YOUR_TICKET_VALUE
、YOUR_GUID_VALUE
、YOUR_SCENE_VALUE
、YOUR_APP_ID_VALUE
、YOUR_AREA_ID_VALUE
、YOUR_PRODUCT_ID_VALUE
、YOUR_CUSTOM_SECURITY_LEVEL
、YOUR_DEVICE_ID
、YOUR_THIRD_LOGIN_EXTERN
、YOUR_MAC_ID
、YOUR_PRODUCT_VERSION
和YOUR_TAG_VALUE
都应该替换为实际的值。 -
这个请求中包含了SsoLogin所需的所有参数和通用参数。
-
在请求中,
host
是目标服务器的主机名或 IP 地址。通常,你需要提供一个正确的host
来指示请求将发送到哪个服务器。在示例代码中,
RequestProcess::SetCommonParam
方法中的以下行设置了request
的host
和port
属性:request->hostName = m_hostName; request->port = m_port;
-
- 这个方法生成一个用于SsoLogin请求的
- 下面是一个简单的示例,展示如何使用
-
-
-
-
-