如何在 .NET Core WebApi 中處理 MultipartFormDataContent 中的文件

在上一篇文章(如何在 .NET Core WebApi 中處理 MultipartFormDataContent)中,我們有描述過如何以最簡單的方式在 .NET Core WebApi 中處理 MultipartFormDataContent 。基於框架層面的封裝,我們可以快速的從 Request.Form 中分別拿到文件內容和文本內容,但是這些默認的解析方式都是建立在前後端以標準的數據格式來進行構建和解析。

問題描述

上圖示例展示了用戶通過 IOS 客戶端發送請求時,對應後端接口接收到的 Request 內容。從請求內容的整體結果,我們可以看出這是一個 multipart/form-data 的數據格式,由於這種數據是由多個 multipart section 組成,所以我們可以看出在這個請求體中,是包含3個 section ,name 值分別爲 Agree,CultureCode,FingerSignature,每個 section 都會包含一個 Content-Disposition 字段,前面兩個 section都是普通的數據格式,最後一個是圖片類型的數據。當後端接口接收到這樣一個請求體時,嘗試使用 Request.Form.Files 的方式來獲取目標文件時,發現無法獲取 FingerSignature 對應的文件內容。

問題分析

通過和客戶溝通,瞭解到FingerSignature 對應的文件是會被一起放到請求體中傳給後端,客戶表示前端APP這一塊的邏輯在後端還沒有升級成 ASP.NET Core(處於 Framework 階段)的時候是可以正常工作的。通過查看ASP.NET Core 中對 Request.Form 的賦值邏輯: FormFeature 實現,找到了如下邏輯函數:

通過源碼的邏輯,我們可以看出,只有當前的 section 對應的 Content-Disposition 同時包含 form-data 和 fileName (或 fileNameStar),纔會被作爲文件來處理(示例:form-data; name="FingerSignature"; fileName=”xxxx.jpeg”),否則並不會把當起的 Section 添加到 Request.Form.Files 中。此時結合上面獲取的請求內容,定位到 FingerSignature 部分的 Content-Disposition 中由於缺少 fileName 字段導致後端無法解析到對應文件爲該issue 的 Root Cause。

解決方案

由於前端 APP 已經發布多個版本,所以讓前端來補全這個字段顯然不是一種穩妥的修復方案,因此後端需要做一個兼容性處理。當遇到這種不是標準格式的文件內容,需要通過 MultipartReader 對象來處理 MultipartFormDataContent 對應的 Section 內容(實際上 Request.Form.Files 底層邏輯就是通過 MultipartReader 來依次解析每個 Section 內容)。這裏實現了一個方法來獲取當前 MultipartFormDataContent 中的所有文件:

在這個方法中有2個細節地方需要注意。

  • 默認情況下,Request.Body 中的內容只允許讀取一次,所以我們需要在使用這個方法的路由地方啓用 EnableBuffering 設置,這裏可以自定義一個 Filter 來複用這種特性:

  • 因爲對 Request.Body開啓 EnableBuffering 了,所以在調用 ReadFilesAsyns 方法的時候,不確定此時 Body 中的 Stream起始位置爲 0。所以我們需要在讀取 Body 之前和之後通過 Seek 方法將 Stream的 Position 重置歸 0。

優化建議

從目前的修復方案來講的話,後端只是提供了一種妥協的修復方案來適配前端的數據不完整,因此感覺比較完善的修復方案是前端在發送 multipart/form-data 的數據時,儘量以標準的方式來構建每個 Section 內容,尤其是文件類型。如果前後端都能以統一的數據格式來進行交互,自然也就不會出現上述所說的這種問題,潛在的風險自然也就變小了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章