HttpWebRequest

这是.NET创建者最初开发用于使用HTTP请求的标准类。HttpWebRequest是老版本.net下常用的,较为底层且复杂,访问速度及并发也不甚理想,但是使用HttpWebRequest可以让开发者控制请求/响应流程的各个方面,如 timeouts, cookies, headers, protocols。另一个好处是HttpWebRequest类不会阻塞UI线程。例如,当您从响应很慢的API服务器下载大文件时,您的应用程序的UI不会停止响应。通常和WebResponse一起使用,一个发送请求,一个获取数据。另外HttpWebRequest库已经过时,不适合业务中直接使用,他更适用于框架内部操作。

/// <summary>
/// HttpWebRequest请求网页示例
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
HttpWebRequest httpWebRequest = null;
HttpWebResponse httpWebResponse = null;
Stream responseStream = null;
string url = "https://www.cnblogs.com/";
try
{
httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(url); //cookie,cookie一般用来验证登录或是跟踪使用
httpWebRequest.CookieContainer = new CookieContainer();
httpWebRequest.CookieContainer.Add(new Cookie() { Name = "test", Value = "test1",Domain="www.cnblogs.com" }); //来源页面
httpWebRequest.Referer = url; //比较重要的UserAgent
httpWebRequest.UserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0 Gecko/20100101 Firefox/52.0"; //请求方法,有GET,POPST,PUT等
httpWebRequest.Method = "GET"; //如果上传文件,是要设置 GetRequestStream
//httpWebRequest.GetRequestStream try
{
httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();
}
catch (System.Net.WebException we)
{
///这个说明服务器返回了信息了,不过是非200,301,302这样正常的状态码
if (we.Response != null)
{
httpWebResponse = (HttpWebResponse)we.Response;
}
} ///得到返回的stream,如果请求的是一个文件或图片,可以直接使用或保存
responseStream = httpWebResponse.GetResponseStream(); ///使用utf8方式读取数据流
StreamReader streamReader = new StreamReader(responseStream, Encoding.UTF8); ///这里是一次性读取,对于超大的stream,要不断读取并保存
string html = streamReader.ReadToEnd();
streamReader.Close();
responseStream.Close();
Console.WriteLine(html.Length);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
if (httpWebRequest != null) httpWebRequest.Abort();
if (httpWebResponse != null) httpWebResponse.Close();
if (responseStream != null) responseStream.Close();
}
}

HttpClient

HttpClient提供强大的功能,提供了异步支持,可以轻松配合async await 实现异步请求,使用HttpClient,在并发量不大的情况,一般没有任何问题;但是在并发量一上去,如果使用不当,会造成很严重的堵塞的情况。

平时我们在使用HttpClient的时候,会将HttpClient包裹在using内部进行声明和初始化,

using(var httpClient = new HttpClient())
{
//other codes
}

在高并发的情况下,连接来不及释放,socket被耗尽,耗尽之后就会出现喜闻乐见的一个错误:

Unable to connect to the remote serverSystem.Net.Sockets.SocketException: Only one usage of each socket address (protocol/network address/port) is normally permitted.

那么如何处理这个问题?“复用HttpClient”即可

  • HttpClientFacotry很高效,可以最大程度上节省系统socket。(“JUST USE IT AND FXXK SHUT UP”:P)
  • Factory,顾名思义HttpClientFactory就是HttpClient的工厂,内部已经帮我们处理好了对HttpClient的管理,不需要我们人工进行对象释放,同时,支持自定义请求头,支持DNS更新等等等

从微软源码分析,HttpClient继承自HttpMessageInvoker,而HttpMessageInvoker实质就是HttpClientHandler。

HttpClientFactory 创建的HttpClient,也即是HttpClientHandler,只是这些个HttpClient被放到了“池子”中,工厂每次在create的时候会自动判断是新建还是复用。(默认生命周期为2min)

还理解不了的话,可以参考Task和Thread的关系

解决方案如下:

IHttpClientFactory

一、可以参考微软官方提供的方法:https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/http-requests?view=aspnetcore-3.1

https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/http-requests?view=aspnetcore-5.0

二、我的解决方案是根据官方提供的方法,选择一种最适合项目的写法进行改造。

1、nuget添加包Microsoft.AspNetCore.Http;

2、startup里ConfigureServices方法添加代码:

services.AddHttpClient();

or

public void ConfigureServices(IServiceCollection services)
{
//other codes services.AddHttpClient("client_1",config=> //这里指定的name=client_1,可以方便我们后期服用该实例 比如已经填写url和header
{
config.BaseAddress= new Uri("http://client_1.com");
config.DefaultRequestHeaders.Add("header_1","header_1"); }); services.AddHttpClient(); //other codes
services.AddMvc().AddFluentValidation();
}

3、可以使用依赖项注入 (DI) 来请求 IHttpClientFactory。 以下代码使用 IHttpClientFactory 来创建 HttpClient 实例:(官方demo)

public class BasicUsageModel : PageModel
{
private readonly IHttpClientFactory _clientFactory; public IEnumerable<GitHubBranch> Branches { get; private set; } public bool GetBranchesError { get; private set; } public BasicUsageModel(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
} public async Task OnGet()
{
var request = new HttpRequestMessage(HttpMethod.Get,
"https://api.github.com/repos/aspnet/AspNetCore.Docs/branches");
request.Headers.Add("Accept", "application/vnd.github.v3+json");
request.Headers.Add("User-Agent", "HttpClientFactory-Sample"); var client = _clientFactory.CreateClient(); var response = await client.SendAsync(request); if (response.IsSuccessStatusCode)
{
using var responseStream = await response.Content.ReadAsStreamAsync();
Branches = await JsonSerializer.DeserializeAsync
<IEnumerable<GitHubBranch>>(responseStream);
}
else
{
GetBranchesError = true;
Branches = Array.Empty<GitHubBranch>();
}
}
}

在实际使用中,我们经常会用NewtonJson序列化,给一个简单的Demo:

string api_domain = _config.GetSection("OuterApi:open-api").Value;
string api_url = $"{api_domain}/common-service/api/basic?code={code}";
var request = new HttpRequestMessage(HttpMethod.Get, api_url);
request.Headers.Add("Accept", "application/vnd.github.v3+json"); var client = _clientFactory.CreateClient(); var response = await client.SendAsync(request); Result<List<OpenApiDictModel>> apiRet = new Result<List<OpenApiDictModel>>();
if (response.IsSuccessStatusCode)
{
string responseStr = await response.Content.ReadAsStringAsync();
apiRet = JsonConvert.DeserializeObject<Result<List<OpenApiDictModel>>>(responseStr);
}

NET 5 使用HttpClient和HttpWebRequest的更多相关文章

  1. WebClient vs HttpClient vs HttpWebRequest

    转载:http://www.diogonunes.com/blog/webclient-vs-httpclient-vs-httpwebrequest/ Just when I was startin ...

  2. c# HttpClient和HttpWebRequest添加Basic类型的Authentication认证

    c#项目中用到调用客户接口,basic身份认证,base64格式加密(用户名:密码)贴上代码以备后用 1.使用HttpClient实现basic身份认证 using (HttpClient clien ...

  3. 如何选择 WebClient,HttpClient,HttpWebRequest

    当我们在用 .NET 调用 RestAPI 时通常有三种选择,分别为:WebClient, HttpWebRequest,HttpClient,这篇文章我们将会讨论如何使用这三种方式去调用 RestA ...

  4. 十二、.net core(.NET 6)添加通用的访问webapi的方法(包括HttpClient和HttpWebRequest)

    开发通用的访问webapi方法. 在common工具文件夹下,新建一个类库项目:Wsk.Core.WebHelper,并引用Package包项目,然后新建一个类HttpClientHelper,用于使 ...

  5. 使用HttpClient实现并发请求

    在.Net 4.0之前,一直是依靠HttpWebRequest实现Http操作的.它默认有一个非常保守的同一站点下最大2并发数限制,导致默认情况下HttpWebRequest往往得不到理想的速度,必须 ...

  6. 关于 C# HttpClient的 请求

    Efficiently Streaming Large HTTP Responses With HttpClient Downloading large files with HttpClient a ...

  7. HttpClient 模拟登陆知乎

    最近做爬虫相关工作,我们平时用HttpWebRequest 比较多,每一个Url都要创建一个HttpWebRequest实例, 而且有些网站验证比较复杂,在登陆及后续抓取数据的时候,每次请求需要把上次 ...

  8. C# HTTP系列1 HttpWebRequest类

    系列目录     [已更新最新开发文章,点击查看详细] .NET Framework 中 System.Net 命名空间下提供了 HttpWebRequest 和 HttpWebResponse 2个 ...

  9. Xamarin.Android之封装个简单的网络请求类

    一.前言 回忆到上篇 <Xamarin.Android再体验之简单的登录Demo> 做登录时,用的是GET的请求,还用的是同步, 于是现在将其简单的改写,做了个简单的封装,包含基于Http ...

随机推荐

  1. Pytest自动化测试 - 简易教程

    简介 pytest是动态编程语言Python专用的测试框架,它具有易于上手.功能强大.可扩展性好.兼容性强.效率高.第三方插件丰富等特点. 功能特征: 完整的文档,包括安装,教程和PDF文档 简单而又 ...

  2. 基于gin的golang web开发:docker

    Golang天生适合运行在docker容器中,这得益于:Golang的静态编译,当在编译的时候关闭cgo的时候,可以完全不依赖系统环境. 一些基础 测试容器时我们经常需要进入容器查看运行情况,以下命令 ...

  3. c语言版单链表

    1 //c语言单链表 2 #include <stdio.h> 3 #include <stdlib.h> 4 typedef struct Node 5 { 6 int da ...

  4. dubbo 扩展点里自动包装

    在看protrocol扩展点时,发现很费解的一点:当前invoker的url是register协议,在export的时候都会从qos->lister->filer这3个包装类开始,看了一下 ...

  5. 区块链V1版本实现之四

    部分程序代码(添加区块): //添加区块 func (bc *BlockChain) AddBlock(data string) { //创建一个区块 //bc.Block的最后一个区块的Hash值就 ...

  6. Visual Studio 连接 SQL Server 关键代码

    首先先把Visual Studio 上面工具打开-->连接数据库-->选择Microsoft SQL Server进入(有两种验证方式:1.windows验证方式[就是本机验证]:2.SQ ...

  7. IdentityServer4系列 | 简化模式

    一.前言 从上一篇关于资源密码凭证模式中,通过使用client_id和client_secret以及用户名密码通过应用Client(客户端)直接获取,从而请求获取受保护的资源,但是这种方式存在clie ...

  8. Promise自定义,看我如何征服你

    自定义代码 这里是我自定义的Promise,如果想看原版,可以跳过最后有符合PromiseA+规范的源码 class 承诺 { constructor(处理器函数) { //1. 处理器函数是在_ne ...

  9. 第14.1节 通过Python爬取网页的学习步骤

    如果要从一个互联网前端开发的小白,学习爬虫开发,结合自己的经验老猿认为爬虫学习之路应该是这样的: 一. 了解HTML语言及css知识 这方面的知识请大家通过w3school 去学习,老猿对于html总 ...

  10. shell 编程 && bash 简介(shell 变量、shell操作环境、数据流重导向、管线命令、shell script)

    如何学习一门编程语言 数据类型 运算符 关键字 1 认识BASH 这个shell linux是操作系统核心,用户通过shell与核心进行沟通,达到我们想要的目的.硬件.核心.用户之间的关系: 原理:所 ...