- 項(xiàng)目源碼
- 原因: 圖片尺寸/大小不一,沒有規(guī)則,總共有300多G
- 目標(biāo)
- 盡量不修改原有程序及架構(gòu), 以最小的代價(jià)使PC時(shí)代的圖片庫(kù)適應(yīng)于移動(dòng)端
- 溯源 (要和源文件對(duì)應(yīng)起來(lái))
- 可控 (預(yù)定義規(guī)則, 并不是隨便進(jìn)來(lái)一個(gè)請(qǐng)求都會(huì)得到處理)
- 不處理第二次(如果已經(jīng)處理過,直接輸出, 否則處理并保存,以供下次請(qǐng)求直接使用)
ASP.NET 和 NETCore 的解決方法不同. 本文分兩部份
ASP.NET
利用
VirtualFile
/VirtualPathProvider
及StaticFileHandler
完成虛擬文件解析.
溯源
溯源的最簡(jiǎn)單辦法是新文件
和源文件
名稱
,路徑
保持一至. 而且有規(guī)則可以依
, 就得把規(guī)則加到文件名中. 綜合以上兩點(diǎn), 可以比較以下幾種訪問方式:
源: http://www.baidu.com/imgs/2017/09/09/abc.jpg
1. http://www.xxx.com/imgs/2017/09/09/abc.auto.s1.jpg
2. http://www.xxx.com/imgs/2017/09/09/abc.jpg?100x100
3. http://www.xxx.com/img?source=/imgs/2017/09/09/abc.jpg&w=100&h=100
- 第1種在文件名和擴(kuò)展名中間插入了占位符
auto
和 規(guī)則s1
. 拿到源文件地址后, 要處理成這種格式的, 不大方便 (僅此而已) - 第2種沒有強(qiáng)插, 但是多了后綴. 這個(gè)的壞處就多了去,
- 首先, 有問號(hào)和沒有問號(hào)的都代表的是同一個(gè)文件,尤其是同時(shí)顯示源圖,和新圖的時(shí)候, 問題更加突出.
- Windows 下, 問號(hào) (
?
) 是不能出現(xiàn)在文件名中的 (Linux 下沒有測(cè)試,不知道). 這條是違背了第4條目標(biāo)的.
- 第3種就不多說(shuō)了,太LOW了,不在考慮范圍內(nèi).
綜上所述, 我們這里選擇第1種訪問方式.
但是要使用這種方式, 就有點(diǎn)為難了, 因?yàn)? 沒有入口 !
給個(gè)入口
靜態(tài)類型的文件,ASP.NET 默認(rèn)不會(huì)經(jīng)過程序處理. 你可以在 Global
的 BeginRequest
里設(shè)置一下斷點(diǎn),看能不能進(jìn)來(lái).
要想要程序可以處理靜態(tài)文件,只需要在 web.config
里加入如下配置:
<system.webServer>
<validation validateIntegratedModeConfiguration="false"/>
<handlers>
<!--設(shè)置可以由該程序處理的文件類型,必須-->
<add name="jpg" path="*.jpg" verb="GET" type="System.Web.StaticFileHandler"/>
<add name="gif" path="*.gif" verb="GET" type="System.Web.StaticFileHandler"/>
<add name="png" path="*.png" verb="GET" type="System.Web.StaticFileHandler"/>
</handlers>
</system.webServer>
至此, 你可以在 Global
的 BeginRequest
里寫處理程序了.
更進(jìn)一層
VirtualPathProvider
, VirtualFile
這兩個(gè)東西的用處很多, 不了解的,可以自行搜索一下.
我了解的也不多, 只是在很久之前用它們?nèi)〕?dll 中的母版頁(yè)而已.這里我用它們來(lái)處理圖片請(qǐng)求.
-
首先, 在
Global
的Application_Start
里注冊(cè)VirtualPathProvider
:HostingEnvironment.RegisterVirtualPathProvider(new VImgProvider(baseDir));
請(qǐng)求進(jìn)入之后,首先會(huì)到
VImgProvider.FileExists
方法, 這里主要是判斷進(jìn)入的請(qǐng)求是不是可接受的圖片類型, 目標(biāo)文件是不是存在.-
然后進(jìn)入
VImgFile.Open
方法 源碼- 判斷請(qǐng)求的文件是否存在, 如果存在,直接返回.
- 如果不存在, 判斷進(jìn)入的請(qǐng)求是否滿足設(shè)定的規(guī)則.
- 如果滿足規(guī)則, 從請(qǐng)求里拆分/解析/裝配
源圖片
的路徑. - 如果
源圖片
存在, 按規(guī)則對(duì)源圖片
進(jìn)行縮放, 并將結(jié)果保存到同一目錄下. - 同樣的請(qǐng)求第二次進(jìn)來(lái),只用走到第1步就可以返回了.
附
為了方便添加修改規(guī)則,我定義了一個(gè)熱插拔的 JsonConfig. 只需要修改 Cfgs/SizeTypes.json
即可:
示例:
{
"Types": [
{
"name": "s1",
"width": 100,
"height": 100,
"quality": 70
},
{
"name": "s2",
"width": 200,
"height": 200,
"quality": 70
},
{
"name": "s3",
"width": 113,
"height": 128
}
]
}
當(dāng)然, 以經(jīng)生成的圖片要手動(dòng)刪除, 才能應(yīng)用新的配置
NETCore
通過修改 StaticFile 中間件的 FileProvider 來(lái)實(shí)現(xiàn).
相對(duì)而言, NETCore 的實(shí)現(xiàn)要簡(jiǎn)單的多: 只需要修改 StaticFileMiddleware 的 FileProvider 即可.
var ap = new AutoImgFileProvider(this.Configuration);
//優(yōu)先 WebRootFileProvider , 如果文件在它中能找得到,就不在去 AutoImageFileProvider 中在找一次了.
var cp = new CompositeFileProvider(env.WebRootFileProvider, ap);
var opt = new StaticFileOptions()
{
FileProvider = cp
};
app.UseStaticFiles(opt);
需要添加 Nuget
- Microsoft.Extensions.FileProviders.Composite
- Microsoft.Extensions.FileProviders.Phyical
AutoImgFileProvider 是對(duì) PhyicalFileProvider
做了一層包裝, 而不是繼承.
收到請(qǐng)求時(shí) (GetFileInfo
), 首先調(diào)用包裝的 PhyicalFileProvider.GetFileInfo
, 如果目標(biāo)存在, 直接返回; 否則, 和ASP.NET的流程一樣: 拆分/解析/組裝/保存, 然后返回.
附
NETCore 規(guī)則配置采用了獨(dú)立的配置文件, 修改規(guī)則,只需修改:
AutoImg.json 即可
示例:
{
"AutoImg": {
"BaseDir": "d:\\Imgs",
"Types": [
{
"name": "s1",
"width": 100,
"height": 100
},
{
"name": "s2",
"width": 200,
"height": 200
},
{
"name": "s3",
"width": 113,
"height": 128
}
]
}
}
另附
NETCore 下圖片處理采用 ImageSharp , NET FX 下用的是 ImageProcessor.
ImageSharp 不支持質(zhì)量百分比.