如何正确发出http Web 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并发出请求即可从表单访问它。

我已经尝试过许多在google上查看过的示例,但不知道为什么我会一直使用此消息。

我是这种算法的新手,如果任何人都可以共享一本书或教程来展示如何做这种事情(解释每个步骤),我将不胜感激

Answers:


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 在您希望使用其他HTTP方法(例如PUT,DELETE和ETC)时
包含参数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异步在您希望使用其他HTTP方法(例如PUT,DELETE和ETC)时
包含参数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
FYI你可能想显示的是如何解析的例子html字符串+1的方式清洁代码..
MethodMan

谢谢,我不了解解压缩,我是php / nodejs开发人员,这是我第一次开始在桌面应用程序上进行开发。
奥斯卡·雷耶斯

不客气,您可能想看看'Newtonsoft.Json'以反序列化检索到的JSON响应。
艾登2014年

有没有机会进行异步版本
艾哈迈德·莫莱(Almad Molaie),2017年

2
@ahmadmolaie添加了它们,以及如何进行POST请求
Aydin

38

另一种方法是使用“ 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日更新: 不建议在“使用”块中使用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
谢谢!对我非常有用。:我只是封闭的反应和“使用”的声明内容修改了一下
codely

5
根据aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong,切勿将HttpClient包装在using语句中。
sfors说恢复Monica's

4
@sfors永不言败。看代码。该HttpClient实例在程序的生命周期内仅被使用一次,并在程序退出之前被处置。那是完全正确和适当的。
Todd Menier

我不确定如何就该文章以及其他有关如何正确创建HttpClient实例的争议。使用私有静态变量,该变量不会被废弃。因此,如该文章中所述:(关于不使用dispose)...“但是HttpClient是不同的。尽管它实现了IDisposable接口,但它实际上是一个共享对象。这意味着在幕后它是可重入的)和线程安全。不要为每次执行创建新的HttpClient实例,而应在应用程序的整个生命周期中共享一个HttpClient实例。”
sfors说恢复Monica 17'December

我意识到我的评论还为时2年,但是Todd并没有反驳这篇文章。Todd只是在说完整的程序示例,在应用程序的生命周期中只使用了一个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。
曼尼沙玛
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.