http 웹 GET 요청을 올바르게 만드는 방법


112

저는 아직 C #에 익숙하지 않으며 알림 (답변, 댓글 등)을받을 때 알려주는이 페이지에 대한 응용 프로그램을 만들려고합니다. 그러나 지금은 사용자의 데이터를 가져올 api에 대한 간단한 호출을 시도하고 있습니다.

저는 Visual Studio Express 2012를 사용하여 C # 응용 프로그램을 빌드하고 있습니다. 여기서 (지금은) 사용자 ID를 입력하면 응용 프로그램이 사용자 ID로 요청하고이 사용자 ID의 통계를 표시합니다.

요청을하려는 코드는 다음과 같습니다.

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

클래스는 객체이며 사용자 ID를 구문 분석하고 요청을 수행하여 양식에서 액세스됩니다.

나는 내가 구글에서 본 많은 예를 시도했지만 왜 내가이 메시지 " "를 모든 방법으로 받고 있는지 단서가 없다.

저는 이런 종류의 알고리즘에 익숙하지 않습니다. 누군가가 이런 종류의 작업을 수행하는 방법을 보여주는 책이나 자습서를 공유 할 수 있다면 (각 단계를 설명하는) 감사하겠습니다.

답변:


247

서버는 때때로 대역폭을 절약하기 위해 응답을 압축합니다.이 경우 응답을 읽기 전에 압축을 풀어야합니다. 다행히 .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();
    }
}

비동기 가져 오기

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 PUT, DELETE, ETC와 같은 다른 HTTP 메소드를 사용하려는 이벤트
의 매개 변수 method를 포함합니다.

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 비동기 PUT, DELETE, ETC와 같은 다른 HTTP 메소드를 사용하려는 이벤트
의 매개 변수 method를 포함합니다.

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.
MethodMan

감사합니다. 저는 압축 해제에 대해 몰랐습니다. 저는 php / nodejs 개발자입니다. 데스크톱 앱에서 개발을 시작한 것은 이번이 처음입니다.
Oscar Reyes

환영합니다. 'Newtonsoft.Json'을 살펴보고 검색 한 JSON 응답을 역 직렬화하는 것이 좋습니다.
Aydin 2014

비동기 버전에 대한 기회가
있습니까

2
@ahmadmolaie 추가 및 POST 요청 수행 방법
Aydin

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

2020 년 6 월 22 일 업데이트 : 포트 고갈을 유발할 수 있으므로 'using'블록에서 httpclient를 사용하지 않는 것이 좋습니다.

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를 포장하지 않습니다.
sfors는 분석 재개 모니카 말한다

4
@sfors 절대로 말하지 마십시오. 코드를보세요. HttpClient인스턴스는 프로그램의 수명을 정확히 한 번만 사용하고, 단지 프로그램이 종료되기 전에 배치된다. 그것은 완전히 정확하고 적절합니다.
Todd Menier

HttpClient의 인스턴스를 올바르게 생성하는 방법에 대해 해당 기사와 다른 기사에 대해 어떻게 이의를 제기 할 수 있는지 잘 모르겠습니다. 폐기되지 않는 개인 정적 변수 사용. 이 때문에 해당 기사에서 인용 한 바와 같이 : (dispose를 사용하지 않는 것과 관련하여) ... "하지만 HttpClient는 다릅니다. IDisposable 인터페이스를 구현하지만 실제로는 공유 객체입니다. 이는 내부적으로 재진입 가능함을 의미합니다.) 및 스레드 각 실행에 대해 새 HttpClient 인스턴스를 만드는 대신 응용 프로그램의 전체 수명 동안 단일 HttpClient 인스턴스를 공유해야합니다. "
sfors는 분석 재개 모니카 말한다

내 의견이 2 년 늦었 음을 알고 있지만 Todd는 기사에 대해 이의를 제기하지 않았습니다. Todd는 단순히 전체 프로그램 예제가 주어지면 응용 프로그램의 수명 동안 단일 HttpClient가 사용된다고 말했습니다.
John

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>을 할당 할 수 없습니다!
Luca Ziegler

그것의 유일한 선언은 null.i는 null을 제거합니다.
마니 샤르마
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.