【问题标题】:How to properly make a http web GET request如何正确发出 http web GET 请求
【发布时间】:2014-11-24 15:27:43
【问题描述】:

我还是 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 上查看的示例,但不知道为什么我会收到这条消息“�”。

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

【问题讨论】:

标签: c# .net httpwebrequest


【解决方案1】:

服务器有时会压缩其响应以节省带宽,发生这种情况时,您需要在尝试读取响应之前对其进行解压缩。幸运的是,.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 async
如果您希望使用 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();
    }
}

【讨论】:

  • 仅供参考,您可能想展示一个示例,说明如何解析html 字符串+1 顺便说一句干净的代码..
  • 谢谢,我不知道解压,我是 php/nodejs 开发者,这是我第一次开始在桌面应用程序上开发。
  • 欢迎您,您可能希望查看“Newtonsoft.Json”以反序列化您检索到的 JSON 响应。
  • 有没有机会异步版本
  • @ahmadmolaie 添加了它们,以及如何进行 POST 请求
【解决方案2】:

另一种方法是像这样使用“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();
        }
    }
}

检查来自stackoverflow的HttpClient vs HttpWebRequest和来自其他的this

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

【讨论】:

  • 谢谢!对我非常有用。我只是通过在“使用”语句中包含响应和内容进行了一些修改:
  • 根据aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong,切勿将 HttpClient 包装在 using 语句中。
  • @sfors 永远不要说永远。看代码。 HttpClient 实例在程序的整个生命周期中只使用一次,并在程序退出之前被释放。这是完全正确和恰当的。
  • 我不确定您如何就如何正确创建 HttpClient 的实例对那篇文章和其他人提出异议。使用私有静态变量,该变量不会被释放。正因为如此,正如那篇文章中所引用的:(关于不使用 dispose)......“但是 HttpClient 不同。虽然它实现了 IDisposable 接口,但它实际上是一个共享对象。这意味着它在幕后是可重入的)和线程安全。与其为每次执行创建一个新的 HttpClient 实例,不如在应用程序的整个生命周期内共享一个 HttpClient 实例。"
  • 我意识到我的评论已经晚了 2 年,但 Todd 并没有对这篇文章提出异议。 Todd 只是说,鉴于完整的程序示例,单个 HttpClient 用于应用程序的整个生命周期。
【解决方案3】:

我认为最简单的方法

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

 var bytes = web.DownloadData(url);

【讨论】:

    【解决方案4】:
    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();
        }
    }
    

    【讨论】:

    • 代码不处理对象;可能是内存泄漏。需要使用语句。
    • 您不能将 分配给隐式类型变量!
    • 它只声明为null。我知道。我删除了null。
    【解决方案5】:

    除了已经给出的回复之外,这是一个点击JSON PlaceHolder 站点的完整示例。

    using System;
    using System.Net.Http;
    using System.Threading.Tasks;
    using Newtonsoft.Json;
    
    namespace Publish
    {
        class Program
        {
            static async Task Main(string[] args)
            {
                
                // Get Reqeust
                HttpClient req = new HttpClient();
                var content = await req.GetAsync("https://jsonplaceholder.typicode.com/users");
                Console.WriteLine(await content.Content.ReadAsStringAsync());
    
                // Post Request
                Post p = new Post("Some title", "Some body", "1");
                HttpContent payload = new StringContent(JsonConvert.SerializeObject(p));
                content = await req.PostAsync("https://jsonplaceholder.typicode.com/posts", payload);
                Console.WriteLine("--------------------------");
                Console.WriteLine(content.StatusCode);
                Console.WriteLine(await content.Content.ReadAsStringAsync());
            }
        }
    
        public struct Post {
            public string Title {get; set;}
            public string Body {get;set;}
            public string UserID {get; set;}
    
            public Post(string Title, string Body, string UserID){
                this.Title = Title;
                this.Body = Body;
                this.UserID = UserID;
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-15
      • 2012-06-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多