C#中的废物 WebRequest

2018-09-10 17:13:29 +08:00
 xiangyuecn

吐槽+骂街贴:吃屎的.net ,一个基本的 http 请求也搞的这么难用,因为一个功能放弃一门(暂且叫语言吧)。

一直用的 WebRequest,直到今天...

1. 完全没法根据需要设定超时

有 Timeout、ReadWriteTimeout ?没用的!看 MSDN 的解释:

https://msdn.microsoft.com/zh-cn/library/system.net.httpwebrequest.timeout(v=vs.110).aspx 域名系统 (DNS) 查询可能需要最多 15 秒钟才能返回或超时。 如果您的请求包含需要解析的主机名,并设置 Timeout 为一个值小于 15 秒,可能需要 15 秒或更长之前 WebException 引发来指示您的请求超时

至少包含一个隐藏的不可控因素,也就是说你没法简单的完全控制请求超时,Timeout 完全是摆设,TMD 的.net 侮辱了 Timeout 这个单词。

ReadWriteTimeout 算是摆设吧,是数据流 read、write 调用超时,意思相近于发送一个直接后等待下一个字节的时间不能超过这个,并非 100%读取完数据和发送完数据的超时控制。然后他默认的 5 分钟完全是废物设定,没错,废物。( java 的 HttpURLConnection 有个设定好像也是如此吧记得)。

没有 ConnectTimeout 选项。没有 ConnectTimeout 选项。没有 ConnectTimeout 选项。(根源所在)

2. 曲线救国 BeginGetRequestStream

使用异步的发送数据流可以变相实现 ConnectTimeout,拿到请求数据流代表已经连上了服务器。

但 GET、HEAD 明确不支持获取 RequestStream。意思就是说 GET 请求你往请求体里面塞东西,.net 就把你写的渣渣代码给干掉,从源头上拒绝你的操作。看到这个逼玩意怎么一个火字了得。

劳资发个请求你还要管我的 method 是什么!

GET 没法拿到请求数据流,GET 没法拿到请求数据流,GET 没法拿到请求数据流。(已经过了底线)

WebRequest 没法实现

比如:严格控制一个 GET 请求耗时在 3 秒以内,超过时间就超时,用来检测 url 是否可以访问。遇到类似 www.google.com 就,,,呵呵了。POST 用 BeginGetRequestStream 没这个问题

要自己实现整体的请求超时功能,他不支持,开个线程也好,开个计时器也好。

GET 不让发请求体,可能很科学,但遇上真不爽

我只是想拿一下发送请求的数据流而已,并非真要往 stream 里面塞数据。

放弃.net

用第三方库解决此类问题?关键是框架给的功能已经能满足 98%的功能了,卡在了这 2%必须实现的功能上而已。用第三方的是不可能的,这辈子都不可能为了这么小小的功能 load 一个 100M 的第三方库的。

so..用 java 吧,或者 php 也行,至少写一个简单的网络请求没这糟心。遇到忍无可忍的地方就换个语言,不是针对.net ,我是说所有的语言!

(文中 C#语言==.net 框架 并非你异议中的 C#语言!=.net 框架,不服去车上拿刀,拿紧)

10774 次点击
所在节点    程序员
84 条回复
cdwyd
2018-09-10 17:58:52 +08:00
c#真是垃圾语言,竟然不能自动赚钱
xiangyuecn
2018-09-10 18:01:38 +08:00
@luozic
@zkd8907
@cdwyd

我也是一个杠精,何况在我自己写的帖子里面,百毒不侵,(doge+滑稽+辣稽
AngelCriss
2018-09-10 18:02:28 +08:00
自己造个轮子不就好了
xupefei
2018-09-10 18:03:04 +08:00
@xiangyuecn 注意你的语气。
Task 是在线程池上的,和 Thread 不一样。Thread 是最重的,但是要说花掉 50ms 我觉得还是不可能的。
fwee
2018-09-10 18:04:36 +08:00
LZ 得换个 GET 能发请求体的语言
xiangyuecn
2018-09-10 18:06:21 +08:00
@xupefei 不要在意其他人的回复,我回复 19 楼是很认真的,task 你没有遇到 task 的线程池占满的情况,不排除永远等待的可能

其他楼层杠的我脾气很暴躁,包涵包涵~
qdwang
2018-09-10 18:15:07 +08:00
.net 库在易用性上确实做的不好,我觉得可能是因为发展的时候,没有得到很多类似楼主这样的反馈的缘故。
xiangyuecn
2018-09-10 18:15:11 +08:00
@fwee 研究 get request body 的时候发现的一篇文章: https://blog.csdn.net/q_an1314/article/details/51298073,我不是要用 GET 来发请求体,而是遇上了需要拿到请求 Stream 才能处理 ConnectTimeout,但 GET 不让拿 RequestStream,导致 GET 部分无解,真遇上了“ GET 不让发请求体”,有点为难
oyjc
2018-09-10 18:35:30 +08:00
开个 socket 自己连接不行么 --!
verrickt
2018-09-10 19:05:54 +08:00
@xiangyuecn
>完全没法根据需要设定超时
查了下,HttpClient 的 timeout 也包含了[DNS 查询]( https://docs.microsoft.com/en-us/dotnet/api/system.net.http.httpclient.timeout?view=netframework-4.7.2#System_Net_Http_HttpClient_Timeout)
不过 LZ 可以试试这样
``` csharp

var client = new HttpClient();
var cts = new CancallationTokenSource();
var task = client.GetAsync("http://example.com",cts.Token);
cts.CancelAfter(TimeSpan.FromSeconds(2));
try
{
var response = await task;
response.EnsureSuccess();
}
catch(TaskCancelldException)
{
// time out
}
```

跟 LZ 一起吐槽,HTTPClient 完全无法得知上传进度。
神奇的是,官方不推荐的的`System.Web.WebClient`和`Windows.Web.Http`是可以得到上传进度的,亲儿子`System.Web.Http`却不行
workaround 有
- 继承`StreamContent `用`SerializeToStreamAsync`去做手脚。
- 写个 Wrapper 流。

两者都非常丑,并且都只能得到流被序列化的进度,无法得到网络传输的进度。


Bonus
[论打开自动更新的重要性]( https://verrickt.github.io/2018/05/21/hell-mode-debugging/)
ShareDuck
2018-09-10 19:08:41 +08:00
先收藏这个主题,回去试试。
xiangyuecn
2018-09-10 19:32:02 +08:00
@verrickt 嗯嗯,HttpClient 和 WebRequest 一个尿性:it may take 15 seconds or more before a WebException is thrown to indicate a timeout on your request,timeout 是不管 dns 解析部分超时

用 CancallationTokenSource 和 @ZhLTE #16 的建议一个意思,HttpClient 有相应方法支持,WebRequest 有点不好办
hellohello123
2018-09-10 20:13:06 +08:00
歪个楼,这个 C# 这门语言有什么关系,明明是类库实现的问题,最多吐槽 .NET
liuguang
2018-09-10 21:35:24 +08:00
哈哈,自己学的不深,不会用也不要把黑锅往语言上扔啊。
https://docs.microsoft.com/zh-cn/dotnet/api/system.net.webrequest.timeout?view=netframework-4.7.2#System_Net_WebRequest_Timeout
timeout 可以设置的。。。
liuguang
2018-09-10 21:37:07 +08:00
下载的话,想要进度条,用 WebClient 啊,异步下载,有各种事件
verrickt
2018-09-10 22:08:13 +08:00
lolizeppelin
2018-09-10 22:10:46 +08:00
get 发流是可以的 用 post 然后覆盖请求方法
标准的 http 服务都会认的
loqixh
2018-09-10 22:22:49 +08:00
get 什么时候不可以发请求体? 用 SendAsync 就可以了
xiangyuecn
2018-09-10 22:26:48 +08:00
@liuguang public abstract class WebRequest

abstract 需要查实现 public class HttpWebRequest : System.Net.WebRequest 然后会发现帖子正文中的引用内容
xiangyuecn
2018-09-10 22:32:33 +08:00
@verrickt 嗯,学习了。IAsyncResult 估计是历史包袱。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/487915

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX