Как правильно сделать HTTP-запрос GET

114

Я все еще новичок в C #, и я пытаюсь создать приложение для этой страницы, которое сообщит мне, когда я получу уведомление (ответил, прокомментировал и т. д.). Но пока я просто пытаюсь сделать простой вызов api, который получит данные пользователя.

Я использую Visual Studio Express 2012 для создания приложения C #, где (на данный момент) вы вводите свой идентификатор пользователя, поэтому приложение будет делать запрос с идентификатором пользователя и отображать статистику этого идентификатора пользователя.

вот код, в котором я пытаюсь сделать запрос:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
//Request library
using System.Net;
using System.IO;

namespace TestApplication
{
    class Connect
    {
        public string id;
        public string type;

        protected string api = "https://api.stackexchange.com/2.2/";
        protected string options = "?order=desc&sort=name&site=stackoverflow";

        public string request()
        {
            string totalUrl = this.join(id);

            return this.HttpGet(totalUrl);
        }

        protected string join(string s)
        {
            return api + type + "/" + s + options;
        }

        protected string get(string url)
        {
            try
            {
                string rt;

                WebRequest request = WebRequest.Create(url);

                WebResponse response = request.GetResponse();

                Stream dataStream = response.GetResponseStream();

                StreamReader reader = new StreamReader(dataStream);

                rt = reader.ReadToEnd();

                Console.WriteLine(rt);

                reader.Close();
                response.Close();

                return rt;
            }

            catch(Exception ex)
            {
                return "Error: " + ex.Message;
            }
        }
        public string HttpGet(string URI)
        {
            WebClient client = new WebClient();

            // Add a user agent header in case the 
            // requested URI contains a query.

            client.Headers.Add("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705;)");

            Stream data = client.OpenRead(URI);
            StreamReader reader = new StreamReader(data);
            string s = reader.ReadToEnd();
            data.Close();
            reader.Close();

            return s;
        }
    }
}

класс является объектом, и к нему можно получить доступ из формы, просто проанализировав его идентификатор пользователя и сделав запрос.

Я пробовал много примеров, которые я смотрел в Google, но не понимаю, почему я получаю это сообщение « » на всех направлениях.

Я новичок в этом алгоритме, если кто-нибудь может поделиться книгой или учебником, который показывает, как делать такие вещи (объясняя каждый шаг), я был бы признателен

Оскар Рейес
источник

Ответы:

250

Серверы иногда сжимают свои ответы, чтобы сэкономить на полосе пропускания, когда это происходит, вам нужно распаковать ответ, прежде чем пытаться его прочитать. К счастью, платформа .NET может делать это автоматически, однако мы должны включить эту настройку.

Вот пример того, как этого добиться.

string html = string.Empty;
string url = @"https://api.stackexchange.com/2.2/answers?order=desc&sort=activity&site=stackoverflow";

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.AutomaticDecompression = DecompressionMethods.GZip;

using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
using (Stream stream = response.GetResponseStream())
using (StreamReader reader = new StreamReader(stream))
{
    html = reader.ReadToEnd();
}

Console.WriteLine(html);

ПОЛУЧИТЬ

public string Get(string uri)
{
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
    request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;

    using(HttpWebResponse response = (HttpWebResponse)request.GetResponse())
    using(Stream stream = response.GetResponseStream())
    using(StreamReader reader = new StreamReader(stream))
    {
        return reader.ReadToEnd();
    }
}

GET async

public async Task<string> GetAsync(string uri)
{
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
    request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;

    using(HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync())
    using(Stream stream = response.GetResponseStream())
    using(StreamReader reader = new StreamReader(stream))
    {
        return await reader.ReadToEndAsync();
    }
}

POST
Содержит параметр methodна случай, если вы хотите использовать другие методы HTTP, такие как PUT, DELETE, ETC

public string Post(string uri, string data, string contentType, string method = "POST")
{
    byte[] dataBytes = Encoding.UTF8.GetBytes(data);

    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
    request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
    request.ContentLength = dataBytes.Length;
    request.ContentType = contentType;
    request.Method = method;

    using(Stream requestBody = request.GetRequestStream())
    {
        requestBody.Write(dataBytes, 0, dataBytes.Length);
    }

    using(HttpWebResponse response = (HttpWebResponse)request.GetResponse())
    using(Stream stream = response.GetResponseStream())
    using(StreamReader reader = new StreamReader(stream))
    {
        return reader.ReadToEnd();
    }
}

    

POST async
Содержит параметр methodна случай, если вы хотите использовать другие методы HTTP, такие как PUT, DELETE, ETC

public async Task<string> PostAsync(string uri, string data, string contentType, string method = "POST")
{
    byte[] dataBytes = Encoding.UTF8.GetBytes(data);

    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
    request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
    request.ContentLength = dataBytes.Length;
    request.ContentType = contentType;
    request.Method = method;

    using(Stream requestBody = request.GetRequestStream())
    {
        await requestBody.WriteAsync(dataBytes, 0, dataBytes.Length);
    }

    using(HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync())
    using(Stream stream = response.GetResponseStream())
    using(StreamReader reader = new StreamReader(stream))
    {
        return await reader.ReadToEndAsync();
    }
}
Айдын
источник
4
кстати, вы можете показать пример того, как разобрать htmlстроку +1на
предмет наличия
спасибо, я не знал о распаковке, я разработчик php / nodejs, и это первый раз, когда я начинаю разрабатывать настольные приложения.
Оскар Рейес
Добро пожаловать, вы можете взглянуть на Newtonsoft.Json, чтобы десериализовать ответ JSON, который вы получаете.
Aydin
есть ли шанс на асинхронную версию
Ахмад Молай
2
@ahmadmolaie Добавил их, а также как делать POST запросы
Айдын
39

Другой способ - использовать HttpClient следующим образом:

using System;
using System.Net;
using System.Net.Http;

namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Making API Call...");
            using (var client = new HttpClient(new HttpClientHandler { AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate }))
            {
                client.BaseAddress = new Uri("https://api.stackexchange.com/2.2/");
                HttpResponseMessage response = client.GetAsync("answers?order=desc&sort=activity&site=stackoverflow").Result;
                response.EnsureSuccessStatusCode();
                string result = response.Content.ReadAsStringAsync().Result;
                Console.WriteLine("Result: " + result);
            }
            Console.ReadLine();
        }
    }
}

HttpClient против HttpWebRequest

Обновление от 22 июня 2020 г .: не рекомендуется использовать httpclient в блоке using, так как это может вызвать исчерпание порта.

private static HttpClient client = null;
    
ContructorMethod()
{
   if(client == null)
   {
        HttpClientHandler handler = new HttpClientHandler()
        {
            AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
        };        
        client = new HttpClient(handler);
   }
   client.BaseAddress = new Uri("https://api.stackexchange.com/2.2/");
   HttpResponseMessage response = client.GetAsync("answers?order=desc&sort=activity&site=stackoverflow").Result;
   response.EnsureSuccessStatusCode();
   string result = response.Content.ReadAsStringAsync().Result;
            Console.WriteLine("Result: " + result);           
 }

Если вы используете .Net Core 2.1+, рассмотрите возможность использования IHttpClientFactory и такой инъекции в свой код запуска.

 var timeout = Policy.TimeoutAsync<HttpResponseMessage>(
            TimeSpan.FromSeconds(60));

 services.AddHttpClient<XApiClient>().ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
        {
            AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
        }).AddPolicyHandler(request => timeout);
КОПАТЬ ЗЕМЛЮ
источник
1
Спасибо! Очень полезно для меня. Я просто немного изменил, заключив ответ и содержимое в оператор using:
codely
5
Согласно aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong , никогда не заключайте HttpClient в оператор using.
sfors требует восстановить Монику на работе
4
@sfors Никогда не говори никогда. Посмотри на код. HttpClientЭкземпляр используется только один раз за жизнь программы и расположен непосредственно перед выходом из программы. Это совершенно правильно и уместно.
Тодд Менье
Я не уверен, как можно оспаривать эту и другие статьи о том, как правильно создать экземпляр HttpClient. Использование частной статической переменной, которая не удаляется. Из-за этого, как цитируется в этой статье: (относительно отказа от использования dispose) ... "Но HttpClient отличается. Хотя он реализует интерфейс IDisposable, на самом деле он является общим объектом. Это означает, что внутри он является реентерабельным) и потоком безопасно. Вместо создания нового экземпляра HttpClient для каждого выполнения вы должны использовать один экземпляр HttpClient в течение всего времени существования приложения ».
sfors говорит восстановить Монику на работе
Я понимаю, что мой комментарий опоздал на два года, но Тодд не оспаривал статью. Тодд просто сказал, что в полном примере программы один HttpClient используется в течение всего срока службы приложения.
Джон
4

Самый простой способ на мой взгляд

  var web = new WebClient();
  var url = $"{hostname}/LoadDataSync?systemID={systemId}";
  var responseString = web.DownloadString(url);

ИЛИ

 var bytes = web.DownloadData(url);
Сергей Кислинский
источник
3
var request = (HttpWebRequest)WebRequest.Create("sendrequesturl");
var response = (HttpWebResponse)request.GetResponse();
string responseString;
using (var stream = response.GetResponseStream())
{
    using (var reader = new StreamReader(stream))
    {
        responseString = reader.ReadToEnd();
    }
}
Маниш шарма
источник
5
код не уничтожает объекты; могла быть утечка памяти. Требуется использование заявлений.
StarTrekRedneck
Вы не можете присвоить <null> неявно типизированной переменной!
Лука Зиглер,
Его только объявляют null. Я знаю, что. I удаляю null.
Маниш Шарма