工程中Http的请求、各种回调函数的使用

文章目录

  • 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,用于返回初始化后的客户端对象。

    具体步骤如下:

    1. 创建一个名为 LoginClient 的客户端对象,并将其指针赋值给 handle,以便调用者可以使用该对象进行后续操作。
    2. 设置一个静态变量 thirdLoginExtern,并将其值设置为 thirdLoginExtern 参数的值。
    3. 调用客户端对象的 Initialize 方法,将参数传递给该方法,以完成客户端的初始化过程。
    4. 返回 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 类的成员变量和回调函数,以便后续可以使用这些信息进行身份验证和与服务器的通信。以下是一些关键操作:

    1. 解析 serverAddrbackupServerAddr,从中获取主机名和端口号,并将它们存储在 m_requestProcess 对象的成员变量中。
    2. 设置应用程序ID (appId)、区域ID (areaId)、组ID (groupId)、地区 (locale)、标签 (tag)、产品ID (productId)、自定义安全级别 (customSecurityLevel) 等信息,也存储在 m_requestProcess 对象的相应成员变量中。
    3. 将各种回调函数存储在 LoginClient 类的成员变量中,以便后续在身份验证和登录过程中使用。
    4. 初始化其他相关的成员变量,如设备ID (m_requestProcess.m_deviceId)、MAC地址 (m_requestProcess.m_macId)、产品版本 (m_requestProcess.m_productVersion) 等。
    5. 最后,调用 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),采取不同的操作。以下是一些关键操作:
    1. 从响应中提取 resultCode,并根据 reqeustCode 的不同来判断处理方式。
    2. 如果请求是一种特定类型的登录请求,如静态登录、自动登录、手机验证码登录等,会提取 autoLoginSessionKeyautoLoginMaxAge
    3. 如果请求是 CodeKey 登录,会提取 inputUserId
    4. 如果请求是 Fcm 登录且结果码为 0,会清除 m_requestProcess 对象的 flowId
    5. 根据 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 对象。以下是它的主要操作:

    1. 创建 HttpThread 对象:m_httpThreadHttpThread 类的实例,它用于处理 HTTP 请求。

    2. 设置超时时间:m_requestProcess.m_timeoutm_requestProcess.m_timeout2 分别设置了两个超时时间,均为 10000 毫秒(10 秒)。

    3. 初始化回调函数:该构造函数初始化了多个回调函数的成员变量,例如 m_checkCodeLoginCallbackm_dynamicLoginCallbackm_fcmLoginCallback 等等。这些回调函数用于处理不同类型的登录和验证请求的响应。

    4. 初始化请求类型到响应处理函数的映射: m_mapResponseFunc 是一个映射,将不同的请求类型与处理它们响应的成员函数绑定在一起。例如,REQ_StaticLogin 对应到 ProcessLoginResponse 函数。

      • 初始化请求类型到响应处理函数的映射是一种机制,它用于将不同种类的请求与相应的处理函数关联起来,以便在收到响应时能够根据请求的类型自动选择正确的处理函数来处理响应数据。

      • **在这段代码中,m_mapResponseFunc 是一个数据结构,可能是一个映射(例如,使用C++的std::mapstd::unordered_map),它将请求类型(通常是一个枚举值)映射到相应的处理函数。**每个处理函数负责处理特定类型请求的响应数据。这是一种非常灵活的方式,可以根据请求类型来选择不同的处理逻辑。

        • 举个例子,如果系统接收到一个登录请求,可以通过该请求的类型(比如 REQ_StaticLogin)查找到相应的处理函数(ProcessLoginResponse),然后将响应数据传递给这个函数来进行处理。这允许系统动态地调用适当的处理函数,以处理不同类型的请求。

        • 这个映射的设置通常在构造函数中进行,以确保在对象创建时建立请求类型到处理函数的关联。这使得代码更具可维护性和可扩展性,因为可以轻松地添加新的请求类型和相应的处理函数,而无需大规模修改现有的代码。

          • 这种通过请求相关枚举值映射到相关函数的方法通常使用了函数指针、函数对象或者回调函数的概念,是一种在C/C++中常见的技术。这种方法之所以有效,是因为在C/C++中,函数是一等公民,可以被视为数据,可以作为参数传递、返回值、存储在数据结构中等。下面是为什么这种方法能够实现的原因:

            1. 函数指针:在C/C++中,您可以声明指向函数的指针,这允许您将函数的地址存储在变量中。枚举值通常被用作索引,来查找与特定请求类型相关的函数指针。
            2. 映射表:开发人员创建了一个映射表,通常是一个关联容器(如std::mapstd::unordered_map),其中枚举值作为键,与之相关的函数指针作为值。这样,您可以根据请求类型查找并调用相应的函数。
            3. 动态分派:通过查找映射表并根据请求类型调用相关函数,实现了动态分派。这意味着在运行时根据实际请求类型来选择要执行的函数,而不需要硬编码条件语句。
            4. 可扩展性:当需要添加新的请求类型时,只需在映射表中添加新的键-值对,无需修改已有的代码。这使得系统更易于扩展。
            5. 逻辑解耦:将请求类型与处理函数分开存储,使代码更加模块化,提高了可读性和维护性。每个函数负责特定请求类型的处理,这种结构降低了复杂性。
            6. 静态类型检查:在编译时,编译器会检查函数指针的类型是否与函数签名匹配,因此能够捕获一些类型错误。
          • 总之,通过将请求相关的枚举值映射到相关函数,您可以使用C/C++的灵活性和函数指针的特性来实现动态的请求分发,这种方法在处理多种请求类型的系统中非常有用。

            • 当你的请求中传递了REQ_StaticLogin的枚举值,系统能够跳转到对应的逻辑实现函数的原因如下:

              1. 映射表: 通常在系统初始化时,开发人员会创建一个映射表(可以是哈希表、字典或其他数据结构),将每个请求类型的枚举值与相应的逻辑实现函数关联起来。这个映射表充当了一个查找请求类型的索引,根据请求类型找到相应的函数指针。
              2. 请求类型: REQ_StaticLogin是一个请求类型的枚举值,它标识了你的请求的种类或目的。在系统内部,这个枚举值被用作一个标识,系统知道这是一个登录请求,而不是其他种类的请求。
              3. 枚举值作为索引: 系统将REQ_StaticLogin的枚举值用作索引,查找映射表,以确定与之相关的逻辑实现函数。
              4. 函数指针: 在映射表中,与REQ_StaticLogin枚举值相关联的函数指针指向了实际的逻辑实现函数。这个函数指针告诉系统在处理REQ_StaticLogin请求时应该执行哪个函数。
              5. 动态分发: 当系统接收到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;
                  }
                  
                  
                  • 在这个示例中,我们使用了命令模式,遥控器接受不同的命令,并在按下按钮时执行它们,而不需要了解具体的设备或命令的实现。这样可以很容易地扩展新的命令和设备,同时保持客户端代码的简洁性。
    5. 创建事件对象: 通过 ::CreateEvent 创建了一个事件对象 m_waitEvent,用于线程同步,此事件最初为非信号状态,后续可以用 SetEvent 将其设置为信号状态,或者用 ResetEvent 将其设置为非信号状态。

    6. 设置其他成员变量的初始状态:这段代码还设置了一些其他成员变量的初始状态,如 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)执行相应的处理函数。下面是这段代码的主要功能:

    1. 首先,它将响应信息(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 参数中。它还可能根据 resultrequestCode 的值执行不同的处理逻辑,但具体的处理逻辑需要查看实际的函数实现。

            这个类和函数的设计用途似乎是为了将响应数据解析为可用的信息,以便后续的处理。可能会有不同的请求和响应处理函数,而 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 函数的具体实现,用于处理响应数据。以下是函数的主要功能:
            1. 如果 result 不等于 0,表示请求处理失败,将相关错误信息存储在 keyValues 中,包括 resultCodefailReasonresultCode 包含错误代码,而 failReason 包含描述失败原因的消息。
            2. 解析 vecCookies 中的 Cookie 信息,将其中的特定 Cookie 名称和值提取到 keyValues 中。这些特定 Cookie 包括:
              • CASTGC:用于存储 tgt 值。
              • CAS_AUTO_LOGIN:用于存储 autoLoginSessionKey 值。
              • CODEKEY:用于存储 codeKey 值。
              • CAS_PUSHMSG_SESSIONKEY:用于存储 pushMsgSessionKey 值。
              • 其他 Cookie:将它们的名称和值一一存储在 keyValues 中。
            3. 针对不同的 requestCode,采用不同的处理逻辑。以下是一些特定请求代码的处理逻辑:
              • 对于 REQ_GetQrCode 请求,如果 response 中没有 codeKey,则将 resultCode 设置为错误代码,否则将 resultCode 设置为 0,并将 picData 存储在 keyValues 中。
              • 对于一些特定请求,如 REQ_CreateWeGameOrderREQ_CreateQQGameOrder 等,将 response 解析为 JSON 格式,提取其中的 resultCodedata。如果 resultCode 为 0,还会提取并存储 data 中的键值对。
              • 对于 REQ_FaceVerifyInitREQ_FaceCodeResultREQ_FaceSendAction 请求,也会解析 response 为 JSON 格式,提取 resultCodedata,并将其存储在 keyValues 中。
              • 对于其他请求,将 response 解析为 JSON 格式,提取 return_codedata,将其存储在 keyValues 中。如果 resultCode 不为 0,还会提取并存储 return_message 作为 failReason
            4. 根据处理结果,将相应的信息存储在 keyValues 中,然后返回 0 表示处理完成。
          • 总之,ResponseProcessProcess 函数用于根据不同的请求代码和响应数据,将关键信息提取并存储在 keyValues 中,以便后续的处理逻辑使用。这种处理响应的方式使代码能够根据请求的不同,以一种通用的方式解析不同格式的响应数据。
            • 这里处理的响应数据通常是 JSON 格式的数据。在具体的处理过程中,会使用 JSON 解析库(在这里似乎使用了 json-c 库)来解析响应数据,提取其中的信息。根据不同的请求和响应结构,会选择不同的字段进行提取和处理。
            • 在代码中,有多个条件分支,针对不同的请求代码(requestCode)来解析 JSON 数据,并提取相应的字段。这种设计可以处理多种不同类型的响应,使代码更加通用和灵活。
    2. 接着,它检查请求代码(requestCode)是否在 m_mapResponseFunc 中有对应的处理函数。这个映射表将请求代码与响应处理函数关联起来。

    3. 如果找到了对应的处理函数(iterFunc != m_mapResponseFunc.end()),则调用相应的处理函数,将请求代码和处理后的数据(keyValues)传递给该函数。

    4. 在处理过程中,根据 isUrl2 的值,设置 keyValues 中的 "isUrl2" 键。

    5. 如果存在等待事件 m_waitEvent,则检查它的状态,如果当前状态不是等待状态(WAIT_OBJECT_0),则设置事件为有信号状态(SetEvent(m_waitEvent))。这可能用于通知等待此事件的其他线程。

    6. 最后,将处理后的 keyValues 映射到 m_mapValList 中,以便后续使用。

  • 总之,这段代码的主要目的是根据请求代码执行相应的响应处理函数,并将处理后的数据存储在 keyValuesm_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 请求和响应。以下是它的主要功能:

    1. 在一个循环中等待事件触发:WaitForSingleObject(m_event, INFINITE),当有请求到达时,会触发这个事件。

    2. 获取请求对象:HttpRequest* request = m_request;,从请求队列中获取一个 HTTP 请求对象。

    3. 处理请求:

      • 发送 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 请求发送和响应接收函数,用于与远程服务器进行通信。
        • 函数定义:

          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 请求的处理过程。以下是它的主要步骤:
            1. 使用 ::InternetOpenA 函数打开一个 Internet 连接,根据 proxyEnable 参数来决定是否使用代理。
            2. 设置回调函数 HttpClient::InternetStatusCallback 以处理连接状态变化。
            3. 使用 ::InternetConnectA 函数连接到指定的主机和端口。
            4. 使用 ::HttpOpenRequestA 函数打开一个 HTTP 请求,根据给定的 HTTP 方法和 URL。
            5. 使用 ::HttpSendRequest 函数发送请求,包括请求的实体数据(如果有的话)。
            6. 等待服务器响应的完成,使用 ::WaitForSingleObject 函数。
            7. 如果状态码不是 200(OK),则返回错误。
            8. 获取响应中的 Cookies,并存储到 vecCookies 中。
            9. 从服务器响应中读取数据,将其存储在 response 变量中。
            10. 最后,关闭所有相关的 Internet 句柄。
          • 这个函数完成了一个完整的 HTTP 请求过程,包括建立连接、发送请求、接收响应和关闭连接。在请求过程中,使用了一些事件(如 m_connEventm_requestEventm_compliteEvent)来等待异步操作完成。
      • 检查请求是否成功:通过 ret 变量来判断请求是否成功,通常 0 表示成功,非 0 表示失败。

      • 处理请求的响应:如果请求成功,将得到响应数据,同时获取到的 Cookie 信息也保存在 vecCookies 中。

      • 通过 m_loginClient->ProcessResponse 处理响应:将请求的结果、请求代码和响应数据传递给 m_loginClient 对象来处理。

    4. 在一些特殊情况下,会进行一些额外的操作,例如获取公钥、切换主机地址、处理备用主机等。这些操作都是为了增加系统的稳定性和容错性。

  • 总之,这段代码实现了一个后台线程,负责发送 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请求,并根据请求的结果设置一些标志和参数。让我一步一步解释:
    1. count 是一个变量,它在前面的代码中定义,但这段代码中没有给出其定义和初始化。这里检查 count 是否等于 0,如果等于 0,表示某种情况下的失败。
    2. 如果 count 等于 0,表示前面的 HTTP 请求失败,代码接着处理以下步骤:
      • request 对象中获取 urlurl2,这取决于它们是否非空(length() > 0),然后将其存储在名为 url 的字符串中。
      • 使用 m_httpClient 对象的 SendHttpRequest 方法,向指定的 hostName2port2 发送 HTTP 请求,使用刚刚获取的 urlrequest->methodrequest->postData 等参数。
      • 将请求的结果(响应数据)存储在 response 变量中,并将响应中的 cookies 存储在 vecCookies 中。
      • isUrl2 设置为 true,表示使用了备用的 url2
    3. 接下来,代码检查 ret 是否不等于 0 并且 request->hostName2 不为空。如果条件成立,它再次执行 HTTP 请求的相同步骤,但这次使用的 URL 依然是 url2
    4. 然后,代码设置了 m_stateSTATE_IDLE,将 m_outUserData 设置为 request->userData,并调用 m_loginClient 对象的 ProcessResponse 方法来处理 HTTP 请求的结果。传递给 ProcessResponse 的参数包括 ret(HTTP 请求的返回码),request->requestCode(请求的代码),response(响应数据),vecCookies(响应中的 cookies),以及 isUrl2 表示是否使用备用 URL。
    5. 最后,代码删除了 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 的实现。它是用于在新线程中执行的入口点函数。以下是关于这段代码的解释:
    1. unsigned _stdcall: 这部分指定了函数的返回类型和调用约定。_stdcall 调用约定用于 Windows 环境,它表示在函数返回时由被调用的函数来清理堆栈。unsigned 表示该函数将返回一个无符号整数。
    2. HttpThread::ThreadEntry(void* param): 这是函数的声明,它接受一个 void* 参数,通常用于传递数据给新线程。在这里,param 参数会传递给新线程,作为指向 HttpThread 对象的指针。
    3. HttpThread* pThis = (HttpThread*)param;: 这一行将 param 转换为 HttpThread 类型的指针 pThis。这是因为 ThreadEntry 函数是静态的,它没有访问实例变量,所以需要将传递的参数转换为 HttpThread 类型的指针,以便在函数内部使用。
      • 在C++中,非静态成员函数通常依赖于类的实例(对象)来访问和操作类的成员变量和方法。静态成员函数则不依赖于类的实例,它们可以直接被类名调用,因此无法访问非静态成员或实例变量。这是因为静态成员函数不与特定的对象实例相关联,它们更像是全局函数,只能访问静态成员和局部变量。
      • 在你的代码中,ThreadEntry 是一个静态成员函数,它用作线程的入口点。线程在启动时需要一个入口点函数,它不能依赖于类的实例,因此必须是静态的。因为它是静态的,所以无法直接访问 HttpThread 类的实例变量或成员函数,除非通过参数传递指向实例的指针(param 参数)。
        • 由于静态成员函数不依赖于类的实例,所以它们无法直接访问或操作类的实例变量或非静态成员函数。为了在静态函数内部访问类的实例相关内容,你可以通过将实例的指针作为参数传递给静态函数来实现。
        • 在你的代码中,ThreadEntry 是一个静态成员函数,它是线程的入口点。当你创建一个线程并指定入口点函数时,通常可以传递一个参数,这个参数是一个指向类实例的指针,这个指针会作为 param 参数传递给 ThreadEntry 函数。
        • 这样做的目的是,通过这个参数,ThreadEntry 函数可以获得对类实例的访问权限,从而可以在静态函数内部访问实例变量和调用实例方法。这是一种在静态函数中访问实例相关内容的常见技巧。这个参数通常被称为上下文参数,它允许将上下文信息传递给静态函数,以便在函数内部使用。
      • 通过将 param 参数转换为 HttpThread 类型的指针,你可以在 ThreadEntry 函数内部访问 HttpThread 对象的成员和方法。这种方式允许你在静态函数中访问实例相关的内容。当线程创建时,通常会将线程入口函数的参数传递给新线程,以便在新线程内部使用。这种方法允许你在多线程环境中执行对象的方法,即使入口点函数是静态的。
    4. 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 类的实例。以下是它的主要功能:
    1. 初始化 m_loginClient 成员,这是一个指向 LoginClient 类的指针,表示将 LoginClient 对象与 HttpThread 关联起来。
    2. 初始化 m_stateSTATE_IDLEm_runningtruem_requestNULLm_proxyEnabletrue,以及其他成员变量的初始值。
    3. 创建一个事件对象 m_event,该事件对象用于线程同步和控制。
    4. 使用 _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 语言的调用约定进行导出和链接。这对于以下情况非常有用:
        1. 兼容性: 当你希望在 C++ 代码中定义的函数可以被其他语言(通常是 C 语言)调用时,extern "C" 可以确保这些函数的命名和参数传递方式与 C 语言的规则相匹配,从而实现兼容性。
        2. 动态链接库(DLL)/共享库(SO)的导出: 在跨编程语言的动态链接库或共享库中,使用 extern "C" 可以确保库的函数和变量可以被其他编程语言的程序正确链接和调用。
        3. 函数名修饰: 在 C++ 中,函数名通常会根据其参数类型进行修饰,这就导致了所谓的 “name mangling”。使用 extern "C" 可以避免这种修饰,保持函数名的原始形式。
        4. C 语言接口的实现: 当你需要为 C 语言的接口实现 C++ 函数时,extern "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 的函数,它接受三个参数:
    1. const char* tgt:这是一个指向 C 风格字符串的指针,通常用于传递目标 TGT(Ticket Granting Ticket)。TGT 是一种用于身份验证的票据。
    2. const char* scene:同样是一个指向 C 风格字符串的指针,通常用于指定身份验证场景或用途。
    3. 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 函数的实现如下:

    1. 首先,它调用了 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 类内部用于存储请求参数的成员变量,通过将外部传递的参数赋值给它,可以在类内的其他方法中使用这些参数来构建请求。

      • 这种设计模式类似于“构建者模式”,其中参数的构建和赋值过程被封装在一个单独的方法中,使得类的使用者可以方便地设置请求参数,同时隐藏了内部的实现细节。

    2. 接下来,它调用 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 登录请求的方法,它接受三个参数:tgtsceneappId。这个函数的主要作用是根据传入的参数构建一个 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 登录请求。这是一个工厂方法,因为它封装了对象的创建细节,根据传递的参数来构造不同的请求对象。

        具体解释如下:

        1. GetSsoLoginRequest 方法接受三个参数:tgt(凭证)、scene(场景)和 appId(应用程序标识)。

        2. 该方法首先创建一个新的 HttpRequest 对象,然后设置其 requestCodeREQ_SsoLogin,表示这是一个 SSO 登录请求。

        3. 然后,根据传递的参数构造请求的 URL。如果 tgt 不为 NULL,则使用传递的 tgt,否则使用 m_tgt 成员变量。sceneappId 也被添加到 URL 中。

        4. SetParamToUrlSetCommonParam 方法用于设置其他请求参数和通用参数,这些参数将影响请求的行为。

          • 函数声明:

            void SetParamToUrl(string& url, map<string, string>* mapReqParams);
            
            • SetParamToUrl 方法用于将请求参数添加到 URL 中。它接受两参数:

              1. url:一个字符串引用,表示要构建的URL。
              2. 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&param2=value2&param3=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。方法的主要步骤如下:

              1. 检查 mapReqParams 是否为 NULL,如果是,直接返回,不进行任何操作。
              2. 使用 for 循环遍历 mapReqParams 中的每个键值对。
              3. 对于每个键值对,首先检查键和值是否都非空(长度大于0)。如果键或值为空,就跳过这个键值对。
              4. 如果 url 的长度大于0,并且不是以问号 ? 结尾,就在 url 后面添加 &,以便将多个参数连接在一起。
              5. 然后,将当前键值对的键和值连接成 "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或请求体中添加特定的参数。

              这个函数会执行以下操作:

              1. 设置请求的方法,如果是GET请求,则设置为"GET",如果是其他HTTP方法,设置为"POST"。
              2. 设置请求的主机名和端口,这通常用于指定要连接的服务器地址和端口号。
              3. 设置请求的超时时间,这是等待服务器响应的最大时间。
              4. 构建URL或POST请求体数据,包括一系列参数,如appIdareaIdlocaleproductIdframeTypeendpointOSversioncustomSecurityLeveldeviceIdthirdLoginExternmacId等。
              5. 如果productVersion不为空,将其编码后添加到URL中。
              6. 如果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_VALUEYOUR_GUID_VALUEYOUR_SCENE_VALUEYOUR_APP_ID_VALUEYOUR_AREA_ID_VALUEYOUR_PRODUCT_ID_VALUEYOUR_CUSTOM_SECURITY_LEVELYOUR_DEVICE_IDYOUR_THIRD_LOGIN_EXTERNYOUR_MAC_IDYOUR_PRODUCT_VERSIONYOUR_TAG_VALUE 都应该替换为实际的值。

                • 这个请求中包含了SsoLogin所需的所有参数和通用参数。

                  • 在请求中,host 是目标服务器的主机名或 IP 地址。通常,你需要提供一个正确的 host 来指示请求将发送到哪个服务器。

                    在示例代码中,RequestProcess::SetCommonParam 方法中的以下行设置了 requesthostport 属性:

                    request->hostName = m_hostName;
                    request->port = m_port;
                    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/110796.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

JavaSE 优先级队列(堆)

目录 1 二叉树的顺序存储1.1 存储方式1.2 下标关系 2 堆(heap)2.1 概念2.2 操作-向下调整2.3 操作-建堆 3 堆的应用-优先级队列3.1 概念3.2 内部原理3.3 操作-入队列(向上调整)3.4 操作-出队列(优先级最高&#xff09;3.5 返回队首元素(优先级最高)3.6 java 中的优先级队列3.7 …

【记录】使用yolov5_obb训练自己的数据集

引言 对于寻常的yolov5目标检测任务&#xff0c;只能检测水平或者垂直的检测框&#xff0c;而对于旋转框的检测却无能为力。为此&#xff0c;在这记录下使用yolov5_obb来训练自己数据集。 一、准备数据集 1、我们先看所需要的数据集文件什么样子&#xff0c;如下图文件夹Sym…

ngx_http_request_s

/* 罗剑锋老师的注释参考&#xff1a; https://github.com/chronolaw/annotated_nginx/blob/master/nginx/src/http/ngx_http_request.h */struct ngx_http_request_s {uint32_t signature; /* "HTTP" */ngx_connection_t …

解决深度学习训练时使用tensorboard http://localhost:6006/无法访问此网站问题

在windows上跑yolov5模型使用了Tensorboard来查看训练过程&#xff0c;开始训练&#xff0c;终端就会提示 直接点击这个网址&#xff0c;就会出现 解决办法是重新开一个终端&#xff0c;激活目前正在使用的虚拟环境&#xff0c;在下面输入 tensorboard --logdir runs\train -…

Leetcode2086. 从房屋收集雨水需要的最少水桶数

Every day a Leetcode 题目来源&#xff1a;2086. 从房屋收集雨水需要的最少水桶数 解法1&#xff1a;贪心 我们可以对字符串 hamsters 从左到右进行一次遍历。 每当我们遍历到一个房屋时&#xff0c;我们可以有如下的选择&#xff1a; 如果房屋的两侧已经有水桶&#xff…

C++ 入门

C关键字 C总计63个关键字&#xff0c;C语言总计32个关键字 命名空间 在c中变量&#xff0c;函数和类都是大量存在的&#xff0c;这些名称都存在于全局作用域中&#xff0c;可能会导致很多冲突&#xff0c;使用命名空间的目的就是对标识符的名称进行本地化&#xff0c;以避免命…

电商零售商家需求预测及库存优化问题(第1问)

电商零售商家需求预测及库存优化问题 数据和题目来源于 2023 年 MathorCup 高校数学建模挑战赛——大数据竞赛 只有第一问&#xff0c;使用ARIMA做预测&#xff0c;使用聚类算法做特征相似性 1 数据读取和处理 1.1 清除重复值 注意附件4要去重&#xff0c;原来是56条数据&am…

一文搞懂“支付·清结算·账务”全局

《上帝视角看支付&#xff0c;总架构解析》 对支付的宏观层面做了分析&#xff0c;详解了整个支付体系每一层的架构和业务模型&#xff0c;而每一层的企业内部支付体系建设是什么样的&#xff1f;会涉及到哪些环节和系统&#xff1f;每个系统会涉及到哪些单据和逻辑&#xff0c…

如何使用 Docker 搭建 Jenkins 环境?从安装到精通

不少兄弟搭 jenkins 环境有问题&#xff0c;有的同学用 window, 有的同学用 mac&#xff0c; 有的同学用 linux。 还有的同学公司用 window, 家里用 mac&#xff0c;搭个环境头发掉了一地。。。 这回我们用 docker 去搭建 jenkins 环境&#xff0c;不管你是用的是什么系统&…

KaiwuDB 亮相第四届跨国公司领导人青岛峰会

10月10日至12日&#xff0c;由商务部和山东省人民政府共同主办的第四届跨国公司领导人青岛峰会在青岛国际会议中心举办。该峰会为跨国公司打造的国家级开放平台&#xff0c;是聚集跨国公司与中国合作、专注跨国公司议题、分享跨国公司经验、链接资源、促进合作的重大活动。Kaiw…

4.多层感知机-2简化版

#pic_center R 1 R_1 R1​ R 2 R^2 R2 目录 知识框架No.1 多层感知机一、感知机1、感知机2、训练感知机3、图形解释4、收敛定理5、XOR问题6、总结 二、多层感知机1、XOR2、单隐藏层3、单隐藏层-单分类4、为什么需要非线性激活函数5、Sigmoid函数6、Tanh函数7、ReLU函数8、多类分…

Spring cloud教程Gateway服务网关

Spring cloud教程|Gateway服务网关 写在前面的话&#xff1a; 本笔记在参考网上视频以及博客的基础上&#xff0c;只做个人学习笔记&#xff0c;如有侵权&#xff0c;请联系删除&#xff0c;谢谢&#xff01; Spring Cloud Gateway 是 Spring Cloud 的一个全新项目&#xff0c;…

如何将你的PC电脑数据迁移到Mac电脑?使用“迁移助理”从 PC 传输到 Mac的具体操作教程

有的小伙伴因为某一项工作或者其它原因由Windows电脑换成了Mac电脑&#xff0c;但是数据和文件都在原先的Windows电脑上&#xff0c;不知道怎么传输。接下来小编就为大家介绍使用“迁移助理”将你的通讯录、日历、电子邮件帐户等内容从 Windows PC 传输到 Mac 上的相应位置。 在…

Leetcode刷题详解——下降路径最小和

1. 题目链接&#xff1a;931. 下降路径最小和 2. 题目描述&#xff1a; 给你一个 n x n 的 方形 整数数组 matrix &#xff0c;请你找出并返回通过 matrix 的下降路径 的 最小和 。 下降路径 可以从第一行中的任何元素开始&#xff0c;并从每一行中选择一个元素。在下一行选择…

UML—时序图是什么

目录 前言: 什么是时序图: 时序图的组成元素&#xff1a; 1. 角色(Actor) 2. 对象(Object) 3. 生命线(LifeLine) 4. 激活期(Activation) 5. 消息类型(Message) 6.组合片段(Combined fragment) 时序图的绘制规则:​ 绘制时序图的3步&#xff1a; 1.划清边界&#xf…

redis-集群切片

切片集群 我曾遇到过这么一个需求&#xff1a;要用 Redis 保存 5000 万个键值对&#xff0c;每个键值对大约是 512B&#xff0c;为了能快速部署并对外提供服务&#xff0c;我们采用云主机来运行 Redis 实例&#xff0c;那么&#xff0c;该如何选择云主机的内存容量呢&#xff…

linux目录与文件管理

目录与路径 关于执行文件路径的变量&#xff1a;$PATH ls完整文件名为&#xff1a;/bin/ls 在任何文件夹下输入ls命令可以显示出一些信息而不是找不到命令&#xff0c;这就是因为环境变量PATH所致。在执行命令时&#xff0c;系统会依照PATH的设置去每个PATH定义的目录下查找文…

【mysql】实现设置表中所有数据的update_time,要求每1000条设置在一天

实现效果示例 执行SQL&#xff1a;&#xff08;mysql 版本查看&#xff1a; select VERSION() &#xff1a;5.7.36-log&#xff09; 实现效果&#xff1a; 这里最后一个id 9 > 总条数 6&#xff0c;所以没有更新到&#xff0c;直接手动补下就行 SELECT * FROM my_test S…

最新ai系统ChatGPT商业运营版网站源码+支持GPT4.0/支持AI绘画+已支持OpenAI GPT全模型+国内AI全模型+绘画池系统

一、AI创作系统 SparkAi创作系统是基于OpenAI很火的ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统&#xff0c;支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如…

全平台七合一万能DIY小程序源码系统 带完整搭建教程

近年来互联网技术的飞速发展&#xff0c;尤其是移动互联网的普及。随着微信、支付宝、百度、抖音、头条等平台的迅速崛起&#xff0c;小程序成为了这些平台上重要的应用形态。这些小程序的应用范围广泛&#xff0c;包括电商、教育、娱乐、生活服务等各个领域。然而&#xff0c;…