部落格又搬家囉,來不及參與本站過去的新同學應該不知"又"搬家的又字而來,先來段白頭宮女話當年好了...

我從 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 雖已有十年歷史,功能、穩定性都很好,架構概念也很專業,再戰十年應不是問題。但我還是決定更換平台展開第三次搬家,有幾個原因:

  1. 2018 年 7 月起,Chrome 開始將未使用 HTTPS 的網站明顯標示「不安全」,並將調降其在搜尋結果中的排名。我比別人卡認真,我比別人卡打拼,為什麼為什麼被說不安全排名比人爛?
    不幸地,我租用的共享式站台空間無法支援 SSL 憑證。

  2. 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 太痛苦,砍掉重練是眼前的較佳解。

  3. 共享式網站租用空間(同一個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 正式啟用。以下是這次搬家歷程的技術筆記:

  1. 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);
    
  2. 在舊站寫了一支程式,將舊文章依新版 Schema 欄位轉成 JSON,再進行必要的資料對應、轉換。新站匯入時直接將 JSON 反序列化回物件陣列,再用 Entity Framework 塞入資料庫,比預期簡單。時代進步,新工具威力愈來愈強大,做起來比以前輕鬆愉很多。

  3. 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 的經驗,之後另外再發文分享。

  4. Miniblog.Core 專案引用了 WebEssentials.AspNetCore.ServiceWorker,網站具備 Progressive Web App 功能,背後有 Service Worker 支援離線使用及優化效能,還能被釘選到手機或平台主畫面當成 App 使用,不過目前沒提供任何訂閱、通知等服務就是了。

  5. Miniblog.Core 用了不少先進的前端技巧,例如:<script> preload/async 載入、圖檔延遲載入(捲到可視範圍才真的下載圖檔)... 等等,我如劉姥姥進大觀園,邊改邊開眼界,看到目瞪口呆。另一方面,十年過去我的前端能力也小有長進,這次改版有留意避開影響效能的寫法。原則上,新版部落格的載入速度與流暢度應該有大幅改進。

  6. 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" }
        };
    });
    
  7. ASP.NET Core 有一套新的 appSettings.json 機制,可在 appSettings..json 加入特定執行環境(例如: 開發、測試、正式)適用的設定,也可透過環境變數、命令列參數指定,蠻靈活的。這部分待未來有更完整心得時再介紹。

  8. 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

  9. 原本 Community Server 內建以 SQL 全文檢索為基礎的站內搜尋功能,SQLite 沒有這種東西。一度考慮改用 Lucene.NET 實作,但考量實作工程不小,目前使用的 ASP.NET Core 能跨 Windows / Linux 平台,一旦引入 Lucene.NET,未來要搬移到 Linux 得多花功夫研究。評估後決定閃開讓專業的來,交給 Google Custom Search,Google 自訂搜尋引擎

  10. 忘了提本次搬家的重要目標,支援 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的內容,太鈍了,我去改程式,謝謝。

Post a comment