AlexXYZ
@AlexXYZ
O Keep Clear O

C#, требуется отправить сырой HTTP(S) запрос?

Всем привет.

Требуется на C# отправить сырой HTTP(S) запрос в том виде как "мать родила":

GET http://HOST:9200/_search HTTP/1.1
Host: HOST:9200

{
    "from" : 0,
    "size" : 10,
    "query" : {
        "indices" : {
            "indices" : ["контрагенты"],
            "query" :{"match_all":{}},
            "no_match_query" : "none"
        }
    },
    "filter" : {
        "and" : [
            {"or" : [{
                    "type" : { "value" : "v" }
            }]},
            {"or" : [{
                "terms":{"ID":["1190"]}
            }]}
        ]
    },
    "highlight" : {
        "fields" : {
            "*" : {}

        }
    }
}

Чтобы никаких анализов имени хоста в коде и т.д. Как в fiddler-composer?
  • Вопрос задан
  • 865 просмотров
Решения вопроса 1
petermzg
@petermzg
Самый лучший программист
Так делаете обычное TCP/IP соединение, т.е. открываете сокет на нужный вам 9200 порт и отсылаете все эти данные.
Вот пример такого соединения
Ответ написан
Пригласить эксперта
Ответы на вопрос 2
Rou1997
@Rou1997
То, что у вас в вопросе, это HTTP-пакет, открывайте подключение TCP/IP и отправляйте, только new line (\n) не забудьте.
Ответ написан
Комментировать
AlexXYZ
@AlexXYZ Автор вопроса
O Keep Clear O
Разобрался!
Маленькая тонкость - сервером выступает ElasticSearch.

Действительно, решение через
new Socket()
правильное. Но! Нужно ООООЧЕНЬ внимательно следить за тем, что пишется в заголовках, а особенно за заголовком "Content-Length: NNN":
1. Обязательно его вставлять, даже если он не указан!
2. Правильно считать длину тела запроса. Не по символам, а по байтам.

Вот переработанный пример кода MS из совета Петр, который уже нормально заработал:

private void btnRequest_Click(object _sender, EventArgs e)
        {
            /* Текстовое поле, из которого я беру текст вида:
GET http://HOST:9200/_search HTTP/1.1
Host: HOST:9200

{
....
    "highlight" : {
        "fields" : {
            "*" : {}

        }
    }
}
           */
            string str = request_text.Text; 
            byte[] bytes = new byte[100024];  // Примерное число, которое надо поменять, если требуется! Мне для экспериментов подошло. В дальнейшем можно будет сделать какой-нибудь ByteStream

            // Connect to a remote device.
            try
            {
                string str_first = str.Split(new char[] { '\r', '\n' })[0];
                string[] arr_str_first = str_first.Split(' ');
                string[] arr_str_address = arr_str_first[1].Split('/');
                Uri uri = (new Uri(arr_str_first[1]));
                string new_str_first = arr_str_first[0] + " /" + arr_str_address.Last() + " " + arr_str_first[2];

                // разделить запрос на две части - заголовки и тело:
                string str_headers = str.Substring(str_first.Length + 2, str.IndexOf("\r\n\r\n") - str_first.Length - 2);
                string str_body = str.Substring(str.IndexOf("\r\n\r\n") + 4);

                int index_substring_content_length = str_headers.IndexOf("Content-Length:");
                if (index_substring_content_length >= 0)
                {
                    string tmp = str_headers.Substring(index_substring_content_length);
                    string[] arr_temp = tmp.Split(new char[] { '\r', '\n' });
                    string sub_string_content_length = arr_temp[0];
                    sub_string_content_length = "\r\n" + sub_string_content_length;
                    Regex regex = new Regex(sub_string_content_length);
                    str_headers = regex.Replace(str_headers, "", 1);
                }

                // Establish the remote endpoint for the socket.
                IPHostEntry ipHostInfo = Dns.GetHostEntry(uri.Host);
                IPAddress ipAddress = ipHostInfo.AddressList[0];
                IPEndPoint remoteEP = new IPEndPoint(ipAddress, uri.Port);

                // Create a TCP/IP  socket.
                Socket sender = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

                // Connect the socket to the remote endpoint. Catch any errors.
                try
                {
                    sender.Connect(remoteEP);

                    Console.WriteLine("Socket connected to {0}", sender.RemoteEndPoint.ToString());

                    string raw_request = new_str_first+"\r\n"+str_headers+ "\r\nContent-Length: "+ Encoding.UTF8.GetBytes(str_body).Length+"\r\n\r\n"+str_body;

                    // Encode the data string into a byte array.
                    byte[] msg = Encoding.UTF8.GetBytes(raw_request); // + "<Client Quit>");

                    // Send the data through the socket.
                    int bytesSent = sender.Send(msg);
                    Console.WriteLine("bytesSent = {0}", bytesSent.ToString());

                    // Receive the response from the remote device.
                    int bytesRec = sender.Receive(bytes); 
                    Console.WriteLine("Echoed test = {0}", Encoding.UTF8.GetString(bytes, 0, bytesRec)); // bytesRec));

                    // Release the socket.
                    sender.Shutdown(SocketShutdown.Both);
                    sender.Close();

                }
                catch (ArgumentNullException ane)
                {
                    Console.WriteLine("ArgumentNullException : {0}", ane.ToString());
                }
                catch (SocketException se)
                {
                    Console.WriteLine("SocketException : {0}", se.ToString());
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Unexpected exception : {0}", ex.ToString());
                }

            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }


Вот результат, который было нужно получить в ответе от сервера:
e9834dff7f9d4bfa849a2f10ae73a9a6.png

Результат получен.

P.S.
Понял, почему не получалось с самого начала. Посмотрев, как Fiddler2 достаточно вольно обращается с синтаксисом запросов в разделе Composer, я и подумал, что и мне так можно. Но, скорее всего, в фоне Fiddler2 всё-таки перерабатывает запрос, стараясь максимально приблизить его к стандарту. Вот пример разницы того, что записано в Composer уменя и что показывает Inspector:

cbe1feb2544f445e8b99fa03a5f306eb.png
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы