Jak poprawnie wykonać żądanie HTTP GET

113

wciąż jestem nowy na C # i próbuję utworzyć aplikację dla tej strony, która powie mi, kiedy otrzymam powiadomienie (odpowiedź, komentarz itp.). Ale na razie próbuję tylko wykonać proste wywołanie interfejsu API, które pobierze dane użytkownika.

Używam programu Visual Studio Express 2012 do tworzenia aplikacji C #, w której (na razie) wpisujesz swój identyfikator użytkownika, więc aplikacja wyśle ​​żądanie z identyfikatorem użytkownika i wyświetli statystyki tego identyfikatora użytkownika.

tutaj jest kod, w którym próbuję wysłać żądanie:

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

klasa jest obiektem, do którego można uzyskać dostęp z formularza, po prostu analizując identyfikator użytkownika i wysyłając żądanie.

Wypróbowałem wiele przykładów, które szukałem w google, ale nie mam pojęcia, dlaczego otrzymuję tę wiadomość „ ” na wszystkie sposoby.

jestem nowy w tego rodzaju algorytmie, jeśli ktoś może udostępnić książkę lub samouczek, który pokazuje, jak robić tego typu rzeczy (wyjaśniając każdy krok), byłbym wdzięczny

Oscar Reyes
źródło

Odpowiedzi:

249

Serwery czasami kompresują swoje odpowiedzi, aby zaoszczędzić na przepustowości, kiedy tak się dzieje, należy zdekompresować odpowiedź przed próbą jej odczytania. Na szczęście framework .NET potrafi to zrobić automatycznie, jednak musimy włączyć to ustawienie.

Oto przykład, jak możesz to osiągnąć.

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

DOSTAĆ

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

POBIERZ asynchronicznie

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
Zawiera parametr methodna wypadek, gdybyś chciał użyć innych metod HTTP, takich jak 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
Zawiera parametr methodw przypadku, gdy chcesz użyć innych metod HTTP, takich jak 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();
    }
}
Aydin
źródło
4
fyi, przy okazji, możesz chcieć pokazać przykład, jak przeanalizować htmlciąg w +1celu uzyskania czystego kodu ..
MethodMan
dziękuję, nie wiedziałem o dekompresji, jestem programistą php / nodejs i po raz pierwszy zaczynam tworzyć aplikacje na komputery stacjonarne.
Oscar Reyes
Witaj, możesz rzucić okiem na „Newtonsoft.Json”, aby zdeserializować pobraną odpowiedź JSON.
Aydin
czy jest jakaś szansa na wersję asynchroniczną
ahmad molaie
2
@ahmadmolaie Dodane je, a także sposób wykonywania żądań POST
Aydin
39

Innym sposobem jest użycie „HttpClient” w następujący sposób:

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

Aktualizacja z 22 czerwca 2020 r .: Nie zaleca się używania httpclient w bloku „using”, ponieważ może to spowodować wyczerpanie portu.

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

Jeśli używasz .Net Core 2.1+, rozważ użycie IHttpClientFactory i wstrzyknięcie w ten sposób w kodzie startowym.

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

 services.AddHttpClient<XApiClient>().ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
        {
            AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
        }).AddPolicyHandler(request => timeout);
KOPAĆ
źródło
1
Dziękuję Ci! Bardzo przydatne dla mnie. Po prostu zmodyfikowałem trochę, załączając odpowiedź i treść w instrukcji „using”:
kodely
5
Według aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong , nigdy nie zawijaj HttpClient w instrukcji using.
sfors mówi, że przywróć Monikę
4
@sfors Never say never. Spójrz na kod. HttpClientInstancja jest używana tylko raz przez cały okres programu i jest umieszczona tuż przed zakończeniem programu. To jest całkowicie poprawne i właściwe.
Todd Menier
Nie jestem pewien, jak można zakwestionować ten artykuł i inne, dotyczące prawidłowego tworzenia wystąpienia HttpClient. Korzystanie z prywatnej zmiennej statycznej, która nie jest usuwana. Z tego powodu, jak cytuję w tym artykule: (dotyczące nieużywania dispose) ... "Ale HttpClient jest inny. Chociaż implementuje interfejs IDisposable, jest to w rzeczywistości obiekt współdzielony. Oznacza to, że pod okładkami jest ponownie wprowadzany) i wątek bezpieczne. Zamiast tworzyć nowe wystąpienie HttpClient dla każdego wykonania, należy udostępniać jedno wystąpienie HttpClient przez cały okres istnienia aplikacji. "
Sfors mówi, że przywróć Monikę
Zdaję sobie sprawę, że mój komentarz jest o 2 lata za późno, ale Todd nie kwestionował tego artykułu. Todd powiedział po prostu, że biorąc pod uwagę przykład pełnego programu, jeden HttpClient jest używany przez całe życie aplikacji.
Jan
4

Najprostszy sposób na moją opinię

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

LUB

 var bytes = web.DownloadData(url);
Сергей Кислинский
źródło
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();
    }
}
Manish Sharma
źródło
5
kod nie usuwa obiektów; może być wyciek pamięci. Musi używać oświadczeń.
StarTrekRedneck
Nie można przypisać <null> do zmiennej o niejawnym typie!
Luca Ziegler
Jej tylko zadeklaruj null. Ja to wiem. Usuń null.
Manish sharma