黑暗執行緒又搬家囉~
27 |
部落格又搬家囉,來不及參與本站過去的新同學應該不知"又"搬家的又字而來,先來段白頭宮女話當年好了...
我從 2004 年 1 月開始寫部落格,如今已堂堂邁入第 14 個年頭。想當年部落格興起,我也趕流行在 PCHome 個人新聞台開了個小站,寫了幾篇廢文瑣事雜文,但跟大部分的人一樣,興頭一過便放著長草。一年後家裡再添一口,再興起繼續發廢文寫點東西的念頭,無奈那陣子個人新聞台系統極度不穩,被內容消失與資料庫錯誤搞到怒火攻心,心一橫便決定搬到有富爸爸 Google 撐腰的 Blogger,這是第一次搬家。
在 Blogger 寫了兩年,初衷只是延伸公司處理問題寫 KB 備忘兼分享的習慣,改成直接把筆記寫在 Internet 上罷了,但不時有路過的高手前輩現身指點,有不少意外收獲,倒也讓我樂此不疲,漸漸寫成習慣。2007 僥倖當選微軟 MVP,深感自己肩負社會責任之重大,部落格應走向更專業化經營(謎之聲:先生,您哪位?),而 Blogger 功能擴充不易、備份與管理困難,自己平日就在寫網站時要風有風,說雨是雨,因系統限制坐困愁城很不是滋味。當時靠著 MVP 前輩 Rex Tang 指點,我也仿效去註冊一個 DNS 網域 (darkthrad.net) 租了網路空間,用 Community Server (ASP.NET WebForm + SQL) 架起部落格跟討論區平台。CS 本身功能十分強大完整且為開源專案,遇到不順眼的小地方可以動手改到開心,加上擁有自己的 Domain Name,跟先前寄宿公共平台爽度完全不同呀~ 第二次搬家的心路歷程當時也有寫筆記留念:漫漫搬家路---
Community Server 從 2007 使用至今超過十年,中間幾度翻修。討論區因使用率偏低而廣告留言嚴重收攤,僅保留部落格功能;初期使用的 Captcha 機制 (TrimothyHumphrey's CAPTCHA) 漸漸不敵垃圾留言,2011 年改裝 reCaptcha 才好一些,但好景不常,2012 年 reCAPTCHA 威風不再,逼得我最後自己寫了陽春 Captcha,網路上現成的垃圾留言攻擊程式瞄準的都是大廠名牌 Captcha,土砲版從來不是鎖定目標,反而較少成為攻擊對象。(但偶爾還是會中)
後續較大的調整是因應 Google 對網站行動裝置相容性的要求,不支援行動瀏覽的網站搜尋排名會受到影響,為此我惡補 CSS,修改排版 HTML 及樣式,胡亂搞了套偽 RWD 才過關。
坦白說,Community Server 雖已有十年歷史,功能、穩定性都很好,架構概念也很專業,再戰十年應不是問題。但我還是決定更換平台展開第三次搬家,有幾個原因:
2018 年 7 月起,Chrome 開始將未使用 HTTPS 的網站明顯標示「不安全」,並將調降其在搜尋結果中的排名。我比別人卡認真,我比別人卡打拼,為什麼為什麼被說不安全排名比人爛?
不幸地,我租用的共享式站台空間無法支援 SSL 憑證。CS 走的是 WebForm + SQL Server,架構考慮周詳且嚴謹,有層層介面隔離邏輯,網頁配置全面元件化,資料庫存取也幾乎都走 Stored Procedure。可想而知,代價是修改擴充手續繁瑣,加個功能得調兩個介面改三支程式。久久才有修改需求,每回都要先溫習一次架構才能動手。我是 KISS (Keep It Simple, Stupid) 法則的忠實信徒,華麗壯觀的架構向來不是我的菜,另一方面,CS 平台仍跑在 .NET 2.0,平日寫程式已用慣 .NET 4.5 / C# 6.0 的各式新函式與語法糖,繼續維護只准用 .NET 2.0/3.5 太痛苦,砍掉重練是眼前的較佳解。
共享式網站租用空間(同一個IIS上掛載多名房客的網站)對機器的控制度很有限,資料備份、Log 分析也諸多不便。Azure 虛擬機器可以登入遠端桌面,操作管理完全比照平日開發測試的實體機,親切方便度壓倒性勝出。能百分之百存取控制機器,安裝申請 SSL 憑證,安裝各家網站平台都不是問題,而我腦中有不少觀察網站行為或實驗的怪點子,都要靠獨立機器才能實現。
大方向已定 - 另建新的部落格網站,跑 Azure 虛擬機器上,然後把舊文章通通搬過去。
下一步是選擇新的部落格系統,沒什麼懸念,我很快就選定 Miniblog.Core,理由很簡單:
第一,它是當今檯面上僅有用 ASP.NET Core 寫的部落格平台,ASP.NET Core 成為主流在即,藉此強迫自己學習上手,是絕佳的安排。
第二,Miniblog.Core 既稱 Mini,架構自然走單純簡潔風,沒有拆出一堆 Interface、Component、Provider 專案,是我鍾愛的 KISS 風格。而作者 Mads Kristensen 是 Visual Studio 神級外掛 WebEssentials 的作者,有什麼比觀摩神人的作品更讓人快速成長呢?(事實也證明,在修改過程中我學到許多新穎觀念與前端技巧,受益良多。)
初步了解 Miniblog.Core,發現它用 XML 保存文章及留言,平時則將所有內容讀入記憶體進行查詢,以個人部落格文章資料量絕對可行。但對於無法用 SQL 工具統計及批次調整,總讓我有些不踏實感,找到在 ASP.NET Core 使用 SQLite + Dapper 的做法後,我決定一鼓作氣將儲存核心由 XML 換成 SQLite,另外陸續調整擴充功能以相容舊版,基本上新部落的雛型就完成了。
利用間暇時間邊做邊學,陸續進行近一個月,新站落成,於 9/21 正式啟用。以下是這次搬家歷程的技術筆記:
Miniblog.Core 是 ASP.NET MVC,要頂替舊站的前題是能將包含 .aspx 的舊 URL 對應到新址,我是用 ASP.NET Core 的 UrlRewriting Middleware ,將有 .aspx 的 URL 統交給 UrlRewriteController,再查表對照轉址。
var rewrite = new RewriteOptions() .AddRewrite("(.+)[.]aspx", "UrlRewrite/Index?path=$1", skipRemainingRules: true); app.UseRewriter(rewrite);
在舊站寫了一支程式,將舊文章依新版 Schema 欄位轉成 JSON,再進行必要的資料對應、轉換。新站匯入時直接將 JSON 反序列化回物件陣列,再用 Entity Framework 塞入資料庫,比預期簡單。時代進步,新工具威力愈來愈強大,做起來比以前輕鬆愉很多。
Miniblog.Core 支援 Live Writer,只需提供網址、帳號、密碼就可以用 Windows Live Writer 或 Open Live Writer 貼文,非常神奇。剖析背後靠的是已屬業界標準的 MetaWeblog 介面,Mininblog.Core 借用第三方套件,MetaWeblog ,NuGet 即可安裝,實作 IMetaWeblogPorivder 再配合 app.UseMetaWeblog("/metaweblog"),網站就有了離線文章編輯功能。不過,我最終決定隨新站上線,也從此改用 Markdown 寫部落格,找到好用的 Markdown Monster (作者 Rick Strahl 是微軟 MVP),能搭配 MetaWeblog 直接發佈,事實上這篇就是我第一篇用 Markdown 寫的部落格文章。關於改用 Markdown 的經驗,之後另外再發文分享。
Miniblog.Core 專案引用了 WebEssentials.AspNetCore.ServiceWorker,網站具備 Progressive Web App 功能,背後有 Service Worker 支援離線使用及優化效能,還能被釘選到手機或平台主畫面當成 App 使用,不過目前沒提供任何訂閱、通知等服務就是了。
Miniblog.Core 用了不少先進的前端技巧,例如:<script> preload/async 載入、圖檔延遲載入(捲到可視範圍才真的下載圖檔)... 等等,我如劉姥姥進大觀園,邊改邊開眼界,看到目瞪口呆。另一方面,十年過去我的前端能力也小有長進,這次改版有留意避開影響效能的寫法。原則上,新版部落格的載入速度與流暢度應該有大幅改進。
ASP.NET Core 不再提供內建 OutputCache 機制,WebEssentials.AspNetCore.OutputCaching 也是 Mads Kristensen 的作品,Miniblog.Core 吃狗食(Dogfooding)也是很合情合理滴。原本苦惱文章更新時要如何強制清除 Cache,後來找到一個超簡單的做法 - 設定 FileDependencies,修改檔案內容,相依的快取都會被清除,下回就會讀到最新內容。
services.AddOutputCaching(options => { options.Profiles["default"] = new OutputCacheProfile { Duration = 3600, FileDependencies = new string[] { "filename.txt" } }; });
ASP.NET Core 有一套新的 appSettings.json 機制,可在 appSettings.
.json 加入特定執行環境(例如: 開發、測試、正式)適用的設定,也可透過環境變數、命令列參數指定,蠻靈活的。這部分待未來有更完整心得時再介紹。 ASP.NET Core 的 Dependency Inject 用得很深,深到你想裝不認識都不行。例如:Controller 要取得文章資料、網站設定,做法是在 Startup.cs 中先註冊服務:
services.AddSingleton<IBlogService, SqliteBlogService>(); services.Configure<BlogSettings>(Configuration.GetSection("blog"));
Controller 建構時將要用到的服務當成參數傳入。
private readonly IBlogService _blog; private readonly IOptionsSnapshot<BlogSettings> _settings; public RobotsController(IBlogService blog, IOptionsSnapshot<BlogSettings> settings) { _blog = blog; _settings = settings; }
在 cshtml 則是寫成 @inject IOptionsSnapshot
settings 原本 Community Server 內建以 SQL 全文檢索為基礎的站內搜尋功能,SQLite 沒有這種東西。一度考慮改用 Lucene.NET 實作,但考量實作工程不小,目前使用的 ASP.NET Core 能跨 Windows / Linux 平台,一旦引入 Lucene.NET,未來要搬移到 Linux 得多花功夫研究。評估後決定閃開讓專業的來,交給 Google Custom Search,Google 自訂搜尋引擎。
忘了提本次搬家的重要目標,支援 HTTPS。我跟大部分的個人網站一樣,選擇免費的 Let's Encrypt 憑證,網路上相關的教學文很多,這裡不多贅述。但 Let's Encrypt SSL 憑證有個缺點是三個月要更新一次,原本想自己寫個程式自動更新,但發現已有佛心的開發者寫好了 - IIS 自動安裝Let’s Encrypt 免費 SSL 並到期自動更新,這部分有空再來研究。
總之,新站已經正式啟用囉,如果大家發現運作有問題,請留言或在 Facebook 貼文反映。
Comments
# by Mark
很棒的經營部落格分享!
# by 打雜菜鳥
黑大:如果只有SCRIPT來載圖的話,不開會看不到文章內的圖檔,可以改成有開啟SCRIPT就延遲載入,沒有的話就直接載入圖檔嗎?,因為有些公司對於SCRIP讀圖會有XSS的疑慮,所以不准開。
# by Jeffrey
to 打雜菜鳥,(驚) 第一次知道有這種封鎖法,能再提供更多一點細節嗎? 所謂有無開啟 Script 是網頁停用 JavaScript?
# by 打雜菜鳥
黑大: 據了解,有幾種做法,不知道對方用哪種技術:1.FIREWALL的 REQUEST規則直接封鎖SCRIPT中,修改預設圖檔路徑行為(類似像LOAD圖換成正確圖檔)。2.直接將SCRIPT換成<NOSCRIPT> 3.如果IMG TAG 封鎖第三方元件載入機制。4.輸出的 REQUEST CONTEXT 不能更動(IMG就永遠都是LOAD圖)
# by Jeffrey
to 打雜菜鳥,依你的說法,伺服器端在送出 Request 前無從知道會不會被動手腳,載入後才會見真章。我想到一個點子,當<img>被封鎖無法動態切換時文章標題下方會多出一個【Fix Image Loading】按鈕,點選會改顯示圖檔靜態載入版。 我沒有環境可實測,有勞你回報這個做法是否管用囉~
# by Ark Chiou
恭喜發財…,core的坑也不少
# by 打雜菜鳥
黑大:請遇到問題的USER測試如下:1.在停用SCRIPT的情況,按鈕按了沒反應。2.這個FIXIMGE在輸出的 REQUEST CONTEXT,可以生效 。3.至於SCRIPT被替換成NOSCRIPT,沒環境可以測,要請其他網友幫忙。
# by Jeffrey
to 打雜菜鳥,狀況 1 的使用者用的是 IE 嗎? 如果是,我八成又踩到 IE 的坑了。剛才再調了一個版本,可請 User 再試試看。(建議用無痕/私密瀏覽排除 Cache 因素,若還是有問題,也請 User 再測一下其他瀏覽器)
# by 小熊子
祝賀黑大喬遷之喜!! 連留言學數學防痴呆也保留~
# by Jeffrey
to 小熊子,真的有防痴呆效果,我常算錯... (羞)
# by Vincent
速度的確快了.
# by Ike
之前有 最新回應的 RSS 現在要去哪訂閱 最新回應 呢?
# by Jeffrey
to lke, (大驚)原來還有人在使用它... 這五斗櫃我以為沒人在乎留在舊家,這幾天我再把它搬回來。
# by 打雜菜鳥
黑大: 我自己測試在停用SCRIPT的情況下,FIRFOX CHROME 內文圖檔都還是顯示LOAD圖案喔 ,按了FIX IMAGE 依然無效
# by Jeffrey
to 打雜菜鳥,我手動停用瀏覽器JavaScript功能的實測結果如後:https://imgur.com/a/TKobzAT ,沒能重現你說的情況,只能靠你再提供更多線索。
# by Jeffrey
to lke, 五斗櫃撿回來了,請按下最新回應標題旁的<del>小鈴噹</del>RSS圖示。
# by Ike
這好重要呢 有新的更新跟問題,都要靠它 感謝黑大 ^^~
# by 打雜菜鳥
黑大,以weird-vbscript-len-issue-again這篇為例: 我找了個網咖測試,在停用SCRIPT和COOKIE的情況下,所有瀏覽器 的所有內文圖檔都還是顯示LOAD圖案喔 ,按了FIX IMAGE 依然無效,舊版只有工商服務的會只剩LOADING圖,內文圖則可以正常顯示。
# by Jeffrey
to 打雜菜鳥,Fix Image是個單純連結,完全不需要依靠JavaScript就可運作,按下後會重連該頁,但網址的/blog/會被改成/Blog/從伺服器端完全停用延遲載入(可參考上次的操作影像:https://imgur.com/a/TKobzAT ),我猜不到無效的原因。如果還有機會再測,請協助留意按Fix Image後網址有無前述改變。(如果你會用瀏覽器F12開發者工具的話,也歡迎提供更多技術細節)
# by 打雜菜鳥
黑大:我找了幾台電腦測,也用F12比較模擬讀取二者的差異: 無法開啟的:<img src="/img/loading.svg" data-src="/Posts/files/Fig1_636732638498942303.gif" alt=""> 可正常修正的<img src="/Posts/files/Fig1_636732638498942303.gif" alt=""> 我問了公司有經常更新瀏覽器的朋友,他們都可用FIXIMGE功能。 所以我懷疑是某些公司的環境禁止沒有完整明確網址的data-src或者瀏覽器還在用舊版,不認得data-src
# by Jeffrey
to 打雜菜鳥,data-src是Miniblog.Core的延遲載入機制,要靠JavaScript把src換成data-src的內容,一旦JavaScript失效,src停在loading.svg,就會一直停在載入中。Fix Img修正原理是切換不一樣的URL(B大寫),此時直接吐出src="/Posts/files/Fig....gif",直接顯示不需JS幫忙。所以關鍵在於按下Fix Img之後沒有重載網頁? URL有沒有換成大寫B? 如果換成大寫B卻仍然看到data-src的版本,我唯一想到的原因是Proxy作怪。
# by 打雜菜鳥
黑大:問過還是無法讀取的公司網管,對方有自訂PROXY SERVER 或者啟用 WEB Chache 或WEB Gzip壓縮功能的情況,我先請對方定期針對黑大的網站重新快取,先觀察看看再說了。
# by Ike
關於 最新回應的 RSS 還有個小問題 就是 author 固定顯示為「service@darkthread.net (Jeffrey Lee)」了 沒辦法知道回應的人是誰 <author>service@darkthread.net (Jeffrey Lee)</author>
# by Jeffrey
to lke, My bad, 程式已修正,謝謝通報。
# by Steven
請問黑大 我也遇上有Cache 問題 , 照您的程式有補上,可是沒效果? FileDependencies = new string[] { "filename.txt" }
# by Jeffrey
to Steven, 資料異動時有更改filename.txt的內容嗎?
# by Steven
感謝黑大 我沒去改filename.txt的內容,太鈍了,我去改程式,謝謝。