我的Minecraft服务器程序遇到了这个令人讨厌的问题。当您尝试登录我的Minecraft服务器时,我尝试从minecraft.com获得登录响应。一切都很好,可以进行设置,例如验证令牌密钥和共享机密。
我只是无法获得获取请求以使用curl :(
这就是我所拥有的:
requestString.append("GET /session/minecraft/hasJoined?username=");
requestString.append(player.Username);
requestString.append("&");
requestString.append("serverId=");
requestString.append(player.loginHash);
requestString.append(" HTTP/1.0\r\n");
std::cout << requestString << std::endl;
curl_easy_setopt(curl, CURLOPT_URL, "https://sessionserver.mojang.com");
list = curl_slist_append(list, requestString.c_str());
list = curl_slist_append(list, "User-Agent: MinecraftServerPP\r\n");
list = curl_slist_append(list, "Connection: close\r\n");
list = curl_slist_append(list, "\r\n");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list);
curl_easy_setopt(curl, CURLOPT_CAINFO, "cacert.pem");
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &_write_data);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
我从服务器上获得了成功,但没有包含所需数据的json对象。
为什么将GET
请求行放在HTTP标头中?它根本不属于那里,实际上libCURL文档甚至指出了这一点:
请求中的第一行(包含方法,通常是GET或POST)不是标头,因此无法使用此选项替换。仅请求行之后的行是标头。在此标题列表中添加此方法行只会导致您的请求发送无效的标题。使用CURLOPT_CUSTOMREQUEST更改方法。
您当前的代码正在发送GET
与此类似的请求:
GET / HTTP / 1.1 主持人:sessionserver.mojang.com GET / session / minecraft / hasJoined?username = <用户名>&serverId = <loginHash> HTTP / 1.0 用户代理:MinecraftServerPP 连接方式:关闭
这就是为什么您没有得到期望的响应的原因。您实际上不是在请求/session/minecraft/hasJoined
资源,而是在实际上在请求根/
资源。
您应该发送这样的GET
请求:
GET / session / minecraft / hasJoined?username = <用户名>&serverId = <loginHash> HTTP / 1.0 主持人:sessionserver.mojang.com 用户代理:MinecraftServerPP 连接方式:关闭
为此,您需要将完整的URL传递给CURLOPT_URL
libCURL并GET
为您处理该行。您可以使用CURLOPT_HTTPGET
以确保GET
实际使用。
另外,CURLOPT_HTTP_VERSION
如果要指定特定的HTTP版本,则应该使用。
此外,虽然你可以使用CURLOPT_HTTPHEADER
的User-Agent
和Connection
标题,你应该是使用CURLOPT_USERAGENT
和CURLOPT_FORBID_REUSE
替代。
尝试以下方法:
url = "https://sessionserver.mojang.com/session/minecraft/hasJoined?username=");
url.append(player.Username); // <-- NOTE: see further below!
url.append("&serverId=");
url.append(player.loginHash); // <-- NOTE: see further below!
std::cout << url << std::endl;
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L);
curl_easy_setopt(curl, CURLOPT_FORBID_REUSE, 1L);
curl_easy_setopt(curl, CURLOPT_CAINFO, "cacert.pem");
curl_easy_setopt(curl, CURLOPT_USERAGENT, "MinecraftServerPP");
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &_write_data);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
如此说来,您还需要考虑其他逻辑以正确处理:CURLOPT_URL
传递指向要使用的URL的指针。该参数应该是一个char *到一个零终止的字符串,该字符串必须以以下格式进行URL编码:
scheme://主机:端口/路径
有关格式的更多说明,请参见RFC 3986。
在发出传输之前,libcurl不会验证语法或使用此变量。即使您在此处设置了一个疯狂的值,
curl_easy_setopt
仍会返回CURLE_OK
。
特别是,RFC的以下部分与您的代码有关:
2.1。百分比编码
当八位字节的相应字符在允许的集合之外或用作组件的定界符或在组件之内时,百分比编码机制用于表示该组件中的数据八位字节。百分比编码的八位位组被编码为一个字符三元组,由百分比字符“%”组成,后跟代表该八位位组的数值的两个十六进制数字。例如,“%20”是二进制八位字节“ 00100000”(ABNF:%x20)的百分比编码,它在US-ASCII中对应于空格字符(SP)。第2.4节介绍了何时应用百分比编码和解码。
pct编码=“%”十六进制十六进制
大写十六进制数字“ A”至“ F”分别等效于小写数字“ a”至“ f”。如果两个URI仅在百分比编码的八位字节中使用的十六进制数字有所不同,则它们是等效的。为了保持一致性,URI生产者和规范化者应对所有百分比编码使用大写十六进制数字。
2.4。何时编码或解码
在正常情况下,唯一的一次对URI中的八位字节进行百分比编码是在从其组成部分生成URI的过程中。这是在实现确定哪些保留字符用作子组件定界符以及哪些可以安全用作数据时。一旦生成,URI始终采用百分比编码形式。
取消引用URI时,必须对方案特定的取消引用过程(如果有的话)重要的组件和子组件进行解析和分离,然后才能安全地解码这些组件中的百分比编码八位字节,否则可能会将数据误认为组件定界符。唯一的例外是与未保留集中的字符相对应的百分比编码八位字节,可以随时对其进行解码。例如,对应于波浪号(“〜”)字符的八位字节通常由较早的URI处理实现编码为“%7E”;可以将“%7E”替换为“〜”,而无需更改其解释。
因为百分号(“%”)用作百分号编码八位位组的指示符,所以必须将该百分号编码为“%25”才能将该八位位组用作URI中的数据。实现不得多次对同一字符串进行百分比编码或解码,因为对已解码的字符串进行解码可能会导致将百分比数据八位位组误解为百分比编码的开始,反之亦然。百分比编码的字符串。
query
URL的组成部分在3.4节中定义:
查询= *(pchar /“ /” /“?”)
pchar
在第3.3节中定义:
pchar =保留/ pct编码/ sub-delims /“:” /“ @”
unreserved
在第2.3节中定义:
未保留= ALPHA / DIGIT /“-” /“。/“ _” /“〜”
sub-delims
在第2.2节中定义:
sub-delims =“!” /“ $” /“&” /“'” /“(” /“)” /“ *” /“ +” /“,” /“;” /“ =”
因此,如果您的player.Username
和player.loginHash
字符串中的任何字符不在这些允许的字符范围内,则在将它们放入URL的查询字符串时,必须对它们进行百分比编码。例如:
std::string encodeForUrlQuery(std::string s)
{
static const char* allowed = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$&'()*+,;=:@/?";
// this is just an example, in practice you should first convert the
// input string to Unicode and charset-encode it, usually to UTF-8,
// and then percent-encode the resulting octets...
std::string::size_type idx = s.find_first_not_of(allowed);
while (idx != std::string::npos)
{
std::ostringstream oss;
oss << '%' << std::hex << std::setw(2) << std::setfill('0') << std::uppercase << (int)s[idx];
std::string encoded = oss.str();
s.replace(idx, 1, encoded);
idx = s.find_first_not_of(allowed, idx+encoded.length());
}
return s;
}
url = "https://sessionserver.mojang.com/session/minecraft/hasJoined?username=");
url.append(encodeForUrlQuery(player.Username));
url.append("&serverId=");
url.append(encodeForUrlQuery(player.loginHash));
std::cout << url << std::endl;
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句