414 - 请求的 uri 太长 - url 长度为 70 个字符
Posted
技术标签:
【中文标题】414 - 请求的 uri 太长 - url 长度为 70 个字符【英文标题】:414 - The requested uri is too long - the url is 70 characters long 【发布时间】:2019-12-11 22:56:22 【问题描述】:我尝试使用 C# 进行身份验证。
它在尝试登录时发送 HTTP GET
请求,如下所示:
https://example.com/clogin.php?name=abc&password=abc
这只是几个字符。但我收到“Request-URI too long”错误。
模拟请求似乎有效,但通过 TcpClient 发送时无效。
ClientManager.cs:
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
using System.IO;
using System.Text;
using System.Diagnostics;
using System.Security.Cryptography.X509Certificates;
using System.Net.Security;
public class ClientManager
private static TcpListener listener;
public static void Main()
ServicePointManager.ServerCertificateValidationCallback = RemoteCertificateValidationCallback;
listener = new TcpListener(IPAddress.Any, 10250);
listener.Start();
Console.WriteLine("*** ClientManager started ***");
Console.WriteLine("Listening to port 10250, make sure not used.");
StartAccept();
while (true)
System.Threading.Thread.Sleep(1000);
string cmd = Console.ReadLine();
if (cmd.Equals("exit"))
Console.WriteLine("*** Stopping cman... ***");
Environment.Exit(0);
if (cmd.StartsWith("auth"))
Console.WriteLine("[" + "simulate" + "] Using auth cred to authenticate.");
char c = '|';
string[] args = cmd.Split(c);
if (!(args.Length > 2))
Console.WriteLine("INVALID_DATA_GIVEN");
string username = args[1];
string password = args[2];
Console.WriteLine("[" + "simulate" + "] Using credentials: " + username + " and " + password);
string response = GetAsync(("https://example.com/clogin.php?name=" + username + "&password=" + password + "&test=1"));
Console.WriteLine("https://example.com/clogin.php?name=" + username + "&password=" + password);
Console.WriteLine(response);
if (response.Equals("ERROR_FAILED_CONNECTION"))
Console.WriteLine("ERROR_SERVERERROR");
else if (response.Equals("INVALID_USERNAME"))
Console.WriteLine("INVALID_DATA_GIVEN");
else if (response.Equals("INVALID_PASSWORD"))
Console.WriteLine("INVALID_DATA_GIVEN");
else if (response.Equals("INVALID_CRED"))
Console.WriteLine("ERROR_AUTH_INVALID_CRED");
else if (response.Equals("IS_BANNED"))
Console.WriteLine("ERROR_AUTH_BANNED");
else
Console.WriteLine("[" + "simulate" + "] LOGIN OK | RESPONSE: " + response);
private static void StartAccept()
listener.BeginAcceptSocket(HandleAsyncConnection, listener);
private static void HandleAsyncConnection(IAsyncResult res)
StartAccept();
TcpClient client = listener.EndAcceptTcpClient(res);
string clientSession = "NULL";
string ip = ((IPEndPoint)client.Client.RemoteEndPoint).Address.ToString();
Console.WriteLine("[" + ip + "] Incoming connection.");
while (true)
try
System.Threading.Thread.Sleep(250);
Console.WriteLine("Trying to read data from " + ip);
NetworkStream stream = null;
Byte[] data = new Byte[8192];
String responseData = String.Empty;
Int32 bytes = 0;
stream = client.GetStream();
bytes = stream.Read(data, 0, data.Length);
Console.WriteLine("Bytes: " + bytes + " Data: " + System.Text.Encoding.ASCII.GetString(data));
responseData = System.Text.Encoding.ASCII.GetString(data);
Console.WriteLine("[" + ip + "] " + responseData);
if (responseData.StartsWith("close"))
Console.WriteLine("[" + ip + "] Connection closed.");
break;
else if (responseData.StartsWith("useauthtoken"))
Console.WriteLine("[" + ip + "] Using auth token to authenticate.");
char c = '|';
string[] args = responseData.Split(c);
if (!(args.Length > 1))
SendMessage(stream, "INVALID_DATA_GIVEN");
string response = GetAsync("http://example.com/cauthtokencheck.php?auth=" + args[1]);
if (response.Equals("yes"))
clientSession = args[1];
SendMessage(stream, "OK");
else
SendMessage(stream, "ERROR_AUTH_INVALID");
else if (responseData.StartsWith("auth"))
Console.WriteLine("[" + ip + "] Using auth cred to authenticate.");
char c = '|';
string[] args = responseData.Split(c);
Console.WriteLine("Data splitted");
if (!(args.Length > 2))
SendMessage(stream, "INVALID_DATA_GIVEN");
string username = args[1];
string password = args[2];
Console.WriteLine("[" + ip + "] Using credentials: " + username + " and " + password);
Console.WriteLine("Logging in...");
string response = GetAsync(("https://example.com/clogin.php?name=" + username + "&password=" + password + ""));
Console.WriteLine("Login attempt completed, with " + response);
if (response.Equals("ERROR_FAILED_CONNECTION"))
SendMessage(stream, "ERROR_SERVERERROR");
else if (response.Equals("INVALID_USERNAME"))
SendMessage(stream, "INVALID_DATA_GIVEN");
else if (response.Equals("INVALID_PASSWORD"))
SendMessage(stream, "INVALID_DATA_GIVEN");
else if (response.Equals("INVALID_CRED"))
SendMessage(stream, "ERROR_AUTH_INVALID_CRED");
else if (response.Equals("IS_BANNED"))
SendMessage(stream, "ERROR_AUTH_BANNED");
else
Console.WriteLine("[" + ip + "] LOGIN OK | RESPONSE: " + response);
if (response == null) response = "Response was null?";
SendMessage(stream, response);
Console.WriteLine("Sended message...");
clientSession = response;
if ((!responseData.StartsWith("auth") || !responseData.StartsWith("useauthtoken") || !responseData.StartsWith("close")) && clientSession.Equals("NULL"))
SendMessage(stream, "ERROR_AUTH_MISSING");
if (responseData.Equals("endGame"))
char c = '|';
string[] args = responseData.Split(c);
if (!(args.Length > 3))
SendMessage(stream, "INVALID_DATA_GIVEN");
string won = args[0];
string kills = args[1];
string singleplayer = args[2];
string response = GetAsync("https://example.com/cgameend.php?session=" + client + "&won=" + won + "&kills=" + kills + "&singleplayer=" + singleplayer);
if (response.Equals("ERROR_FAILED_CONNECTION"))
SendMessage(stream, "ERROR_SERVERERROR");
else if (response.Equals("SESSION_INVALID"))
SendMessage(stream, "ERROR_AUTH_MISSING");
else if (response.Equals("SUCCESS"))
SendMessage(stream, "SUCCESS");
catch (Exception e)
Console.WriteLine("[" + ip + "] Connection closed: " + e.Message);
break;
public static string GetAsync(string uri, Action<WebHeaderCollection> headers = null)
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
//request.Headers.Set(HttpRequestHeader.ContentLocation, uri);
//request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
Console.WriteLine(request.RequestUri);
using (HttpWebResponse response = (HttpWebResponse) request.GetResponse())
using (Stream stream = response.GetResponseStream())
using (StreamReader reader = new StreamReader(stream))
return reader.ReadToEnd();
public static void SendMessage(NetworkStream stream, string msg)
Byte[] sendBytes = Encoding.ASCII.GetBytes(msg);
stream.Write(sendBytes, 0, sendBytes.Length);
public static bool RemoteCertificateValidationCallback(System.Object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
bool isOk = true;
return isOk;
clogin.php:
<?php
$conn = new mysqli("localhost", "root", "not-the-real-password", "topdown");
if ($conn->connect_error)
die("ERROR_FAILED_CONNECTION");
$name = $_GET["name"];
$password = $_GET["password"];
function generateRandomString($length = 10)
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$charactersLength = strlen($characters);
$randomString = '';
for ($i = 0; $i < $length; $i++)
$randomString .= $characters[rand(0, $charactersLength - 1)];
return $randomString;
function endsWith($haystack, $needle)
$length = strlen($needle);
if ($length == 0)
return true;
return (substr($haystack, -$length) === $needle);
$sql = "SELECT `password`,`banned` FROM `accounts` WHERE `name`='".$name."';";
$result = $conn->query($sql);
if ($result->num_rows < 1)
die("INVALID_CRED");
die();
$found = "";
$banned = false;
while($row = $result->fetch_assoc())
$found = $row["password"];
$banned = $row["banned"];
if($found == $password)
if($banned==1)
die("IS_BANNED");
$session = generateRandomString(16);
$sql = "UPDATE `accounts` SET `clientsession`='".$session."' WHERE `name`='".$name."'";
if ($conn->query($sql) === TRUE)
die($session);
else
die("ERROR_FAILED_CONNECTION");
else
die("INVALID_CRED");
?>
【问题讨论】:
是否有任何重定向?那些很容易变成这个巨大的。也可能是登录表单和登录表单目标是两个不同的文件,并且登录表单只是在获得任何参数时抛出异常(几个 HTTP 参数太长了)。 服务器是否还没有准备好接受请求?我试过了,页面看起来非常“即将推出”。 @Christopher nope,它只是用于登录的 api 页面。不是真正的登录页面。 @Christopher 并且没有重定向。curl
和这个 URL 没有出现这样的错误。而且您没有提供代码,因此不清楚您的请求与我尝试的有何不同。除此之外:请不要将文本(错误)包含在图像中 - 将文本粘贴到问题中。
【参考方案1】:
您的模拟没有反映您在非模拟情况下向服务器发送的内容,这就是您无法在模拟中重现错误的原因。
在模拟的情况下,您读取了一行,字符串 cmd
的长度就是该行的长度。在非模拟情况下,您改为读取大小为 8192 字节的缓冲区 data
。这意味着如果您阅读auth|abc|abc
的响应,data
的内容将是auth|abc|abc\0\0\0\0....
,即服务器发送的内容,然后是8180(8192-12)个字符\0
(即\x00
,@ 987654328@ 或者这可以用 C# 编写)。
在您的responseData.Split
之后,密码(即args[2]
)因此不会像您预期的那样是abc
,而是abc\0\0\0\0....
。这再次意味着应该是https://....?user=abc&pass=abc
的URL 实际上是https://....?user=abc&pass=abc\0\0\0....
。 \0
需要使用 URL 编码编码为 %00
导致 https://....?user=abc&pass=abc%00%00%00....
而且所有这些 8180 %00
将在 URL 中单独产生 24540 个字符,这解释了为什么服务器会抱怨 URL 太大。查看服务器访问日志或错误日志也可能会显示此类问题。
【讨论】:
我该如何解决这个问题? @GoldenretriverYT:bytes
已经包含已读取的字节数。确保只对这种大小的字符串进行操作(例如使用Substring
)。
感谢您的回答,解决了问题。【参考方案2】:
该消息来自服务器,而不是客户端。有关可能的解决方案,请参阅此答案: How do I resolve a HTTP 414 "Request URI too long" error?
【讨论】:
不,不能是服务器。尝试使用您的网络浏览器访问此站点 - 没有问题。 @GoldenretriverYT:“不,不能成为服务器。” - 确实如此。仔细查看您得到的错误,它清楚地显示“远程服务器返回错误:(414)”。 @SteffenUllrich 再次 - 你可以使用你的网络浏览器 - 没有问题 - 那么它到底应该是服务器吗? @GoldenretriverYT:您的请求很可能与浏览器请求不同,也与我尝试使用curl
的请求不同。服务器可以对不同的请求发送不同的响应。不幸的是,您没有提供任何类型的代码,因此无法说出您所做的不同以及可能导致服务器响应不同的原因。
@GoldenretriverYT:欢迎来到互联网。您需要了解为什么我们会欺骗用户代理字符串。 en.wikipedia.org/wiki/User_agent#User_agent_spoofing以上是关于414 - 请求的 uri 太长 - url 长度为 70 个字符的主要内容,如果未能解决你的问题,请参考以下文章
如何为 nginx 请求设置允许的 url 长度(错误代码:414,uri 太大)
是否可以增加 HttpClient 中的最大 URL 长度? (无效的 URI:uri 字符串太长)