NET 5 使用HttpClient和HttpWebRequest
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的更多相关文章
- WebClient vs HttpClient vs HttpWebRequest
转载:http://www.diogonunes.com/blog/webclient-vs-httpclient-vs-httpwebrequest/ Just when I was startin ...
- c# HttpClient和HttpWebRequest添加Basic类型的Authentication认证
c#项目中用到调用客户接口,basic身份认证,base64格式加密(用户名:密码)贴上代码以备后用 1.使用HttpClient实现basic身份认证 using (HttpClient clien ...
- 如何选择 WebClient,HttpClient,HttpWebRequest
当我们在用 .NET 调用 RestAPI 时通常有三种选择,分别为:WebClient, HttpWebRequest,HttpClient,这篇文章我们将会讨论如何使用这三种方式去调用 RestA ...
- 十二、.net core(.NET 6)添加通用的访问webapi的方法(包括HttpClient和HttpWebRequest)
开发通用的访问webapi方法. 在common工具文件夹下,新建一个类库项目:Wsk.Core.WebHelper,并引用Package包项目,然后新建一个类HttpClientHelper,用于使 ...
- 使用HttpClient实现并发请求
在.Net 4.0之前,一直是依靠HttpWebRequest实现Http操作的.它默认有一个非常保守的同一站点下最大2并发数限制,导致默认情况下HttpWebRequest往往得不到理想的速度,必须 ...
- 关于 C# HttpClient的 请求
Efficiently Streaming Large HTTP Responses With HttpClient Downloading large files with HttpClient a ...
- HttpClient 模拟登陆知乎
最近做爬虫相关工作,我们平时用HttpWebRequest 比较多,每一个Url都要创建一个HttpWebRequest实例, 而且有些网站验证比较复杂,在登陆及后续抓取数据的时候,每次请求需要把上次 ...
- C# HTTP系列1 HttpWebRequest类
系列目录 [已更新最新开发文章,点击查看详细] .NET Framework 中 System.Net 命名空间下提供了 HttpWebRequest 和 HttpWebResponse 2个 ...
- Xamarin.Android之封装个简单的网络请求类
一.前言 回忆到上篇 <Xamarin.Android再体验之简单的登录Demo> 做登录时,用的是GET的请求,还用的是同步, 于是现在将其简单的改写,做了个简单的封装,包含基于Http ...
随机推荐
- C++基础练习1
1 /* 2 //读入一个双精度浮点数,保留12位小数输出这个浮点数. 3 #include<iostream> 4 #include <iomanip> 5 using na ...
- 冲刺随笔——Day_Six
这个作业属于哪个课程 软件工程 (福州大学至诚学院 - 计算机工程系) 这个作业要求在哪里 团队作业第五次--Alpha冲刺 这个作业的目标 团队进行Alpha冲刺 作业正文 正文 其他参考文献 无 ...
- celery异步发送短信
1.使用celery异步发送短信 1.1 在 celery_task/mian.py 中添加发送短信函数 # celery项目中的所有导包地址, 都是以CELERY_BASE_DIR为基准设定. # ...
- 简单dp水题
#include <bits/stdc++.h> using namespace std; #define limit (100 + 5)//防止溢出 #define INF 0x3f3f ...
- webpack系列:webpack小老弟接了个简单活
webpack深入浅出系列:进阶篇 前沿,本篇文章的讲解思路是以webpack的五大核心为线索,以webpack对象为第一视角来讲述(以前记得看过一个文笔非常厉害的技术啊婆写的,非常有趣.然后我就想着 ...
- 基于spring@aspect注解的aop实现
第一步:编写切面类 package com.dascom.hawk.app.web.tool; import org.aspectj.lang.JoinPoint; import org.aspect ...
- java ipv6发邮件需要注意的点
和ipv4发邮件一样,毕竟ip只是用来找地址的,v4 v6使用上基本没区别. 但有一点得注意:java ipv6采用发送RST包来通知邮件服务器断开连接,这样会导致客户端抛 MessagingExce ...
- 什么是Python迭代器?
迭代器(Iterator):迭代器可以看作是一个特殊的对象,每次调用该对象时会返回自身的下一个元素,从实现上来看,一个迭代器对象必须是定义了__iter__()方法和next()方法的对象. Pyth ...
- Python中sort、sorted的cmp参数废弃之后使用cmp_to_key实现类似功能
Python2.1以前的排序比较方法只提供一个cmp比较函数参数,没有__lt__等6个富比较方法, Python 2.1引入了富比较方法,Python3.4之后作废了cmp参数.相应地从Python ...
- 第15.16节 PyQt(Python+Qt)入门学习:PyQt中的信号(signal)和槽(slot)机制以及Designer中的使用
老猿Python博文目录 老猿Python博客地址 一.引言 前面一些章节其实已经在使用信号和槽了,但是作为Qt中最重要的机制也是Qt区别与其他开发平台的重要核心特性,还是非常有必要单独介绍. 二.信 ...