Como fazer uma solicitação HTTP GET corretamente


112

Ainda sou novo no c # e estou tentando criar um aplicativo para esta página que me avisará quando receber uma notificação (respondida, comentada, etc.). Mas, por enquanto, estou apenas tentando fazer uma chamada simples para a API que obterá os dados do usuário.

Estou usando o Visual studio express 2012 para construir o aplicativo C #, onde (por enquanto) você insere seu id de usuário, para que o aplicativo faça a solicitação com o id de usuário e mostre as estatísticas deste id de usuário.

aqui está o código em que estou tentando fazer a solicitação:

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;
        }
    }
}

a classe é um objeto e está sendo acessada a partir do formulário apenas analisando o ID do usuário e fazendo a solicitação.

Tentei muitos dos exemplos que procurei no google, mas não faço ideia por que estou recebendo de todas as formas a mensagem " ".

Eu sou novo neste tipo de algoritmo, se alguém puder compartilhar um livro ou tutorial que mostra como fazer esse tipo de coisa (explicando cada etapa), eu agradeceria

Respostas:


247

Os servidores às vezes compactam suas respostas para economizar largura de banda; quando isso acontece, você precisa descompactar a resposta antes de tentar lê-la. Felizmente, o .NET framework pode fazer isso automaticamente, no entanto, temos que ativar a configuração.

Aqui está um exemplo de como você pode conseguir isso.

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);

OBTER

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 assíncrono

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
Contém o parâmetro methodno caso de você desejar usar outros métodos HTTP, como 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
Contém o parâmetro methodcaso você deseje usar outros métodos HTTP, como 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
Você pode querer mostrar um exemplo de como analisar a htmlstring +1para código limpo a propósito ..
MethodMan

obrigado, não sabia sobre a descompactação, sou desenvolvedor php / nodejs e esta é a primeira vez que começo a desenvolver aplicativos para desktop.
Oscar Reyes

Bem-vindo, você pode querer dar uma olhada em 'Newtonsoft.Json' para desserializar a resposta JSON que você recupera.
Aydin

há alguma chance de versão assíncrona
ahmad molaie

2
@ahmadmolaie Adicionados, bem como como fazer solicitações POST
Aydin

39

Outra maneira é usar 'HttpClient' assim:

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 vs HttpWebRequest

Atualização de 22 de junho de 2020: não é recomendado usar httpclient em um bloco 'usando', pois isso pode causar o esgotamento da porta.

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);           
 }

Se estiver usando .Net Core 2.1+, considere usar IHttpClientFactory e injetar assim em seu código de inicialização.

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

 services.AddHttpClient<XApiClient>().ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
        {
            AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
        }).AddPolicyHandler(request => timeout);

1
Obrigado! Muito útil para mim. Eu apenas modifiquei um pouco, incluindo a resposta e o conteúdo na instrução "usando":
codely

5
Por aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong , nunca envolva o HttpClient em uma instrução using.
sfors diz restabelecer Monica em

4
@sfors Nunca diga nunca. Olhe o código. A HttpClientinstância é usada exatamente uma vez durante a vida útil do programa e é descartada pouco antes de o programa ser encerrado. Isso é completamente correto e apropriado.
Todd Menier de

Não sei como você pode contestar esse artigo e outros sobre como criar corretamente uma instância do HttpClient. Usando uma variável estática privada, que não é descartada. Por causa disso, conforme citado naquele artigo: (com relação a não usar dispose) ... "Mas HttpClient é diferente. Embora implemente a interface IDisposable, na verdade é um objeto compartilhado. Isso significa que, por baixo do pano, é reentrante) e thread seguro. Em vez de criar uma nova instância de HttpClient para cada execução, você deve compartilhar uma única instância de HttpClient para toda a vida útil do aplicativo. "
sfors diz restabelecer Monica em

Percebo que meu comentário está 2 anos atrasado, mas Todd não contestou o artigo. Todd estava simplesmente dizendo que, dado o exemplo de programa completo, um único HttpClient é usado durante a vida útil do aplicativo.
John

4

Maneira mais simples para minha opinião

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

OU

 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
o código não descarta objetos; pode ser um vazamento de memória. Precisa usar declarações.
StarTrekRedneck

Você não pode atribuir <null> a uma variável digitada implicitamente!
Luca Ziegler

É apenas declarar null.i saber que.i remover null.
Manish sharma
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.