Skip to content

Commit c233cdd

Browse files
committed
优化获取服务器返回的文件名
1 parent a0e9adf commit c233cdd

3 files changed

Lines changed: 78 additions & 8 deletions

File tree

src/dotnetCampus.FileDownloader.Tool/Program.cs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.IO;
3+
using System.Net.Http;
34
using System.Runtime.InteropServices.ComTypes;
45
using System.Threading.Tasks;
56
using CommandLine;
@@ -21,20 +22,29 @@ static async Task Main(string[] args)
2122

2223
// https://www.speedtest.cn/
2324
var url =
24-
"https://speedtest1.gd.chinamobile.com.prod.hosts.ooklaserver.net:8080/download?size=25000000&r=0.2978374611691549";
25+
"https://node-103-27-27-20.speedtest.cn:51090/download?size=25000000&r=0.625866791098137";
2526
url =
26-
"https://download.jetbrains.8686c.com/resharper/ReSharperUltimate.2020.1.3/JetBrains.ReSharperUltimate.2020.1.3.exe";
27+
"https://download.jetbrains.com/resharper/dotUltimate.2025.1/JetBrains.dotUltimate.2025.1.exe";
2728
//var md5 = "7d6bbeb6617a7c0b7e615098fca1b167";// resharper
2829

2930
//url = "http://localhost:5000";
31+
32+
// 这里的 gitdl.cn 是 iFileProxy 离线下载工具的地址,这是一个非常好的工具。开源地址: https://git.linxi.info/xianglin_admin/iFileProxy
33+
url = "https://gitdl.cn/https://github.com/srwi/EverythingToolbar/releases/download/1.5.2/EverythingToolbar-1.5.2.msi";
34+
35+
//url =
36+
// "https://down.pc.yyb.qq.com/pcyyb/packing/14e1e37f997f49a58d560ab97fa335aa/pcyyb_2702800040_installer.exe";
37+
//url = "https://pm.myapp.com/invc/xfspeed/qqpcmgr/download/QQPCDownload320001.exe";
38+
//// 这个地址带了 Content-Disposition 头,文件名是从这个头中获取的
3039
url =
31-
"https://dscache.tencent-cloud.cn/upload//ES_686_194-4f155229efeef75bb9c9a3995060c766dc0eac28.png";
40+
"https://sw.pcmgr.qq.com/2f472366ca30d8ac1ad4acb64c77d2ad/680c8f51/spcmgr/download/BaiduNetdisk_txgj1_7.50.0.132.exe";
41+
//url = "https://pc-package.wpscdn.cn/wps/download/W.P.S.60.1955.exe";
3242

33-
var file = new FileInfo(@"File.txt");
43+
var downloadFolder = new DirectoryInfo(@"DownloadFolder");
3444

3545
var progress = new Progress<DownloadProgress>();
3646

37-
await FileDownloaderHelper.DownloadFileAsync(url, file, progress:progress);
47+
await FileDownloaderHelper.DownloadFileToFolderAsync(url, downloadFolder, progress:progress);
3848
#endif
3949
await Task.Delay(100);
4050
});

src/dotnetCampus.FileDownloader/DownloadByHttpClient/SegmentFileDownloaderByHttpClient.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,12 @@ private static SocketsHttpHandler CreateDefaultSocketsHttpHandler()
136136
//{
137137
// return ValueTask.FromResult(context.PlaintextStream);
138138
//}
139+
140+
// 忽略证书错误
141+
//SslOptions =
142+
//{
143+
// RemoteCertificateValidationCallback = (sender, certificate, chain, errors) => true
144+
//}
139145
};
140146

141147
return socketsHttpHandler;

src/dotnetCampus.FileDownloader/FileDownloaderHelper.cs

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
#if NETCOREAPP3_1_OR_GREATER
99
using System.Net.Http;
10+
using System.Text.RegularExpressions;
11+
using System.Net.Http.Headers;
1012
#endif
1113
using System.Runtime.InteropServices;
1214
using System.Security.AccessControl;
@@ -168,14 +170,66 @@ protected override async Task<HttpResponseMessage> GetResponseAsync(HttpRequestM
168170
var response = await base.GetResponseAsync(request);
169171
if (string.IsNullOrEmpty(ServerSuggestionFileName))
170172
{
173+
ServerSuggestionFileName = TryGetServerSuggestionFileName();
174+
}
175+
176+
return response;
177+
178+
string? TryGetServerSuggestionFileName()
179+
{
180+
var httpContentHeaders = response.Content.Headers;
181+
182+
if (httpContentHeaders.ContentDisposition == null)
183+
{
184+
return null;
185+
}
186+
187+
// {Last-Modified: Mon, 30 Dec 2024 09:27:04 GMT
188+
// Content-Type: application/octet-stream
189+
// Content-Disposition: attachment; filename*="UTF-8''BaiduNetdisk_txgj1_7.50.0.132.exe"
190+
// Content-Length: 403338840
191+
// }
192+
// 这里拿到的 nameValueHeaderValue 可能就取出
193+
NameValueHeaderValue? nameValueHeaderValue =
194+
httpContentHeaders.ContentDisposition.Parameters.FirstOrDefault(t => t.Name == "filename*");
195+
var fileNameValue = nameValueHeaderValue?.Value;
196+
if (!string.IsNullOrEmpty(fileNameValue))
197+
{
198+
// 额外判断一下 UTF-8 存在的情况
199+
var match = Regex.Match(fileNameValue, @"([\S\s]*)''([\S\s]*)");
200+
if (match.Success)
201+
{
202+
var encodingText = match.Groups[1].Value;
203+
var fileNameText = match.Groups[2].Value;
204+
if (string.Equals("utf-8", encodingText, StringComparison.OrdinalIgnoreCase))
205+
{
206+
// 以下转码用于防止中文名乱码
207+
var unescapeDataString = Uri.UnescapeDataString(fileNameText);
208+
return unescapeDataString;
209+
}
210+
}
211+
else
212+
{
213+
// 匹配不上,那就应该是整个都是文件名了
214+
return fileNameValue;
215+
}
216+
}
217+
218+
var fileName = httpContentHeaders.ContentDisposition.FileName;
219+
if (!string.IsNullOrEmpty(fileName))
220+
{
221+
return fileName;
222+
}
223+
171224
if (response.Headers.TryGetValues("Content-Disposition", out var contentDispositionTextEnumerable) && contentDispositionTextEnumerable.FirstOrDefault() is { } contentDispositionText)
172225
{
173-
ServerSuggestionFileName =
226+
// 正常不会放在这里的,都是在 Content 的 Header 里面的
227+
return
174228
WebResponseHelper.GetFileNameFromContentDispositionText(contentDispositionText);
175229
}
176-
}
177230

178-
return response;
231+
return null;
232+
}
179233
}
180234
}
181235
#else

0 commit comments

Comments
 (0)