.Net 如何修改 HttpHeaders 中的 Content-Disposition

陝西顏值扛把子發表於2021-09-13

最近在看一些.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) || 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!");
            }
            
        }

我需要修改 HttpHeadersContent-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) || 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,轉載請註明來源

相關文章