最近在看一些.Net5的內容,於是就想將之前Spring寫的一個項目遷移到.Net上來看看。
不得不說.Net這幾年發展的確實挺好的,超快的啟動速度,極佳的性能讓它一點不比Java差,但確實在國內生態有一些問題,一些問題的答案確實不那么好找,就比如我先在遇到的這個問題。
問題一:如何修改Content-Disposition屬性
一個簡單下載查看文件的功能,我可以選擇下載還是查看本地的文件,代碼非常簡單,就像這樣:
/// <summary>
/// 加載文件
/// </summary>
/// <param name="path">文件路徑</param>
/// <param name="type">加載模式</param>
/// <returns>文件</returns>
[Route("file")]
[HttpGet]
public async Task<IActionResult> DownloadFile(string path, string type)
{
if (string.IsNullOrEmpty(path))
{
return Content("404 for not found!");
}
try
{
var filePath = PathFilterUtil.PathFilter(RUN_PATH, path);
var memoryStream = new MemoryStream();
using (var stream = new FileStream(filePath, FileMode.Open))
{
await stream.CopyToAsync(memoryStream);
}
memoryStream.Position = 0;
// 獲取文件的ContentType
string fileExt = Path.GetExtension(path);
var provider = new FileExtensionContentTypeProvider();
var memi = provider.Mappings[fileExt];
if (type == "inline")
{
Response.Headers.Add("Content-Disposition", $"inline; filename={Path.GetFileName(filePath)}");
return File(memoryStream, memi, Path.GetFileName(filePath));
}
return File(memoryStream, memi, Path.GetFileName(filePath));
}
catch (DirectoryNotFoundException e)
{
_logger.LogError($"文件:{path},沒有找到!\n{e.Message}");
return Content("404 for not found!");
}
}
我需要修改 HttpHeaders
中 Content-Disposition
屬性,將默認的 attachment
根據需要變成 inline
,但是我按照上面的說法,怎么都改不了它的 Content-Disposition
屬性,不論則樣它永遠返回的是Content-Disposition: attachment; filename=appsettings.json; filename*=UTF-8''appsettings.json
這樣。
通過查找資料
期間我嘗試了將Response.Headers.Add()
方法變成Response.Headers.Append()
,我甚至在百度看見了 Response.AddHeader()
這種早已過時的方法,真滴離譜。
后來我終於在stackoverflow上找到了答案,不得不說還是stackoverflow強。
if (type == "inline")
{
Response.Headers.Add("Content-Disposition", $"inline; filename={Path.GetFileName(filePath)}");
return File(memoryStream, memi);
}
方法很簡單,刪除return File(memoryStream, memi, Path.GetFileName(filePath));
后面 Path.GetFileName(filePath)
這個獲取文件名的方法就好。
問題二:中文文件下載報InvalidOperationException: Invalid non-ASCII or control character in header:
錯
這個不多說了,就是編碼的問題,在Response.Headers.Add("Content-Disposition", $"inline; filename={Path.GetFileName(filePath)}");
寫入文件名時,不能直接寫入文件,需要進行轉碼,這個轉碼的方法我又查了好久,最后還是在stackoverflow找到的,這兩個問題真的是體現出了.Net在國內發展不咋地。
這要是Java,隨便一查答案就出來了。
具體解決就是使用System.Net.WebUtility.UrlEncode()
對文件名進行重新編碼。像這樣
if (type == "inline")
{
Response.Headers.Add("Content-Disposition", $"inline; filename={System.Net.WebUtility.UrlEncode(Path.GetFileName(filePath))}");
return File(memoryStream, memi);
}
完整代碼
/// <summary>
/// 加載文件
/// </summary>
/// <param name="path">文件路徑</param>
/// <param name="type">加載模式</param>
/// <returns>文件</returns>
[Route("file")]
[HttpGet]
public async Task<IActionResult> DownloadFile(string path, string type)
{
if (string.IsNullOrEmpty(path))
{
return Content("404 for not found!");
}
try
{
var filePath = PathFilterUtil.PathFilter(RUN_PATH, path);
var memoryStream = new MemoryStream();
using (var stream = new FileStream(filePath, FileMode.Open))
{
await stream.CopyToAsync(memoryStream);
}
memoryStream.Position = 0;
// 獲取文件的ContentType
string fileExt = Path.GetExtension(path);
var provider = new FileExtensionContentTypeProvider();
var memi = provider.Mappings[fileExt];
_logger.LogInformation($"當前請求訪問下載文件目錄:{filePath} {Path.GetFileName(filePath)}");
if (type == "inline")
{
Response.Headers.Add("Content-Disposition", $"inline; filename={System.Net.WebUtility.UrlEncode(Path.GetFileName(filePath))}");
return File(memoryStream, memi);
}
return File(memoryStream, memi, Path.GetFileName(filePath));
}
catch (DirectoryNotFoundException e)
{
_logger.LogError($"文件:{path},沒有找到!\n{e.Message}");
return Content("404 for not found!");
}
}
版權
本文首發於https://www.buguagaoshu.com/archives/net%E5%A6%82%E4%BD%95%E4%BF%AE%E6%94%B9heepheaders,轉載請注明來源