如何創建高性能移動web站點
如果你的網站3秒鐘沒有響應,人們就會失去興趣了。為了滿足響應快這個愿望,需要一個不同的方法在手機上進行分析,設計和測試。
這篇文章將會對Johan Johansson在2013年4月提出" 怎樣讓你的網站在手機上也很快"的這種理念進行擴展。我們將提出論證方法來確認人們在手機上與網站的交互方式和以前是不一樣的,特別是設計也是基于此理念的。我們的目標不僅僅是提高網站性能,而且也要增加客戶收入的。
我們將關注手機兩個特性,這兩個特性短期內也不會有變化:電池容量小,屏幕小。
電量小
手機的通訊要用無線電,但手機的電池很小,所以要非常謹慎的用電以防止把電用光。這樣,如果無線電不用的時候就會迅速關掉,這樣就增加了網頁出現的時間。 2G和3G無線技術需要2秒鐘來建立HTTP鏈接。如果我接受“用戶會在3秒后失去興趣”的觀點的話,那我們的網站只有1秒來響應了。想想這“黃金般的一 秒”吧。
最大化利用這“黃金一秒”
小屏幕
在物理世界中,廣告牌和雜志的內容都是根據媒介的大小和觀看距離來定制的。在數字世界中,一個典型的中檔智能手機擁有幾乎6平方英寸大小的屏幕。15英寸的MacBook Pro電腦屏幕擁有超過100平方英寸的大小。這樣,我們不僅可以通過減少發送到手機端的內容優化網站性能,而且可以優化業務流程來提高網站所有者的投資回報。
本文的代碼示例是由.NET提供。我已經在companion article文章中展示了用PHP, Java, C 和Python達到同樣的效果。我在這篇文章的結尾會解釋為什么選用.NET。
最大化利用 “黃金一秒”
網站設計者和開發者們常常想當然的認為用戶應該用高帶寬Wi-Fi和固網來連接。響應式網站設計(RWD)強制在不同設備上(不論其性能好壞)顯示相同的內容、導航和業務流程,限制了創新。
確保我們能夠容易的進行性能測量,進行用戶行為監控的基于不同設備特性的解決方案以及低帶寬設備網頁訪問優化都需要最大限度的利用這“黃金一秒”。
模擬現實網絡
現實移動帶寬模擬測試是一個必不可少的移動Web性能測試。很多100美元以下的廉價無線路由都提供了限制帶寬功能,測試僅僅只涉及到了局域網內的客戶端的上行和下行帶寬限制功能。如果路由不支持這個功能話,那么試試用 DD-WRT(DD-WRT是一個開源升級固件,可以替代目前主流路由的默認操作系統)來限制帶寬。
我用DD-WRT升級了Linksys E3000路由。路由升級的過程非常簡單,DD-WRT官網上提供了完整的說明。
安裝好DD-WRT后去到QoS菜單,啟用帶寬限制。設置上行和下行帶寬的值,我習慣將下行帶寬設置為256kbps,上行帶寬設置為28kbps來模擬移動網絡的平均帶寬。
現在無論是以Wi-Fi或網線連接到路由器的設備的帶寬都被人為的限制了。我們可以監視帶寬實際的使用情況。
雖然這種測試方法并沒有包括隨機的掉線、可變帶寬條件和由信號強弱引起的延遲等情況,但是比起你在快速、低延遲帶寬下做的其他測試效果要好。在網站開發初 期,這是一個在開發過程中對Web性能進行非正式測試的簡單的方法,能夠確保你在正式測試過程中不出現任何討厭的問題。
你不能管理所不能測量的事
管理顧問 Peter Drucker 曾經說過一句名言:“如果你無法測量某件事,你就無法管理它。”
持續根據設備特性(比如無線支持或屏幕大小)對用戶查看的內容進行監控,或多或少將會有助于你識別手機上流行的內容和服務。也許你將看不到任何區別,但是除非你測量過,否則無法確定。
好的日志
Google Analytics 提供了一些關于設備模型的信息,但它缺乏我們需要基于屏幕尺寸和輸入方法作出明智決定的細節。幸運的是,一個全面的設備檢測庫(DDR)可以將此信息添加到現有日志文件中。下面的代碼片段可以添加到 .NET網站中,參考51degrees.mobi(可通過 NuGet ) 獲取屏幕的物理尺寸和輸出到一個簡單的CSV文件中。
- // Write a log file containing the current time, and the screen
- // size of the requesting device in inches.
- File.AppendAllText(
- Path.Combine(
- AppDomain.CurrentDomain.BaseDirectory, String.Format(
- "App_Data\\Simple_Log_{0:yyyyMMdd}.csv",
- DateTime.UtcNow)),
- String.Format("{0:s},{1},{2},{3}\r\n",
- DateTime.UtcNow,
- Request.Path,
- Request.Browser["ScreenInchesWidth"],
- Request.Browser["ScreenInchesHeight"]));
第一行是處理請求的日期和時間。第二行是請求的頁面。最后兩行是設備屏幕的寬度和高度。抓取足夠多的數據和平均屏幕的尺寸大小繪制出了下面的圖表:
比較設備屏幕的平均大小超過20個月
分析可以縮小到具體的頁面。有關設備的特性,操作系統和瀏覽器也可以被添加到列中。
類似的代碼可以使用PHP、Java、Python和其他環境語言。
已有的日志文件
有時,已有的Web頁面不能按照上面的方式修改。在這樣的情況下,DDR可以用來執行含有用戶代理的日志日文的離線分析了。下面的.NET代碼是一個實用 的命令行程序,它解析空格分隔的日志文件,然后計算出日志所表示的請求以平方英尺為單位的平均屏幕尺寸。第一個參數是日志文件的位置,第二個參數是日志文 件里用戶代理所在列的索引。
- using System;
- using FiftyOne.Foundation.Mobile.Detection.Binary;
- using System.IO;
- namespace ConsoleApplication
- {
- class Program
- {
- static void Main(string[] args)
- {
- // The number of devices read from the log file.
- int count = 0;
- // The column in the input file the user agent is held in.
- int column = int.Parse(args[1]);
- // Screen dimension variables.
- double total = 0, width, height, squareInches;
- // Create a provider to determine the device capabilities.
- var provider = Reader.Create("51Degrees.mobi.dat");
- // Read each line of the log file provided in argument 0.
- // Assume the value at column 8 is the UserAgent string.
- using (var reader = File.OpenText(args[0]))
- {
- while(reader.EndOfStream == false)
- {
- var values = reader.ReadLine().Split(new[] { ' ' });
- if (values.Length >= column)
- {
- // Get the device information based on the UserAgent.
- var device = provider.GetDeviceInfo(
- values[column - 1].Replace("+", " "));
- if (device != null)
- {
- // Determine the screen dimensions in inches.
- double.TryParse(
- device.GetFirstPropertyValue("ScreenInchesWidth"),
- out width);
- double.TryParse(
- device.GetFirstPropertyValue("ScreenInchesHeight"),
- out height);
- squareInches = width * height;
- // If valid values are available (not a desktop/laptop)
- // then add the values to the results.
- if (squareInches > 0)
- {
- total += squareInches;
- count++;
- }
- }
- }
- }
- }
- Console.WriteLine(
- "Average screen size '{0:#.00}' square inches from '{1}' devices",
- total / count,
- count);
- Console.ReadKey();
- }
- }
- }
分析日志文件很不準確,因為除了用戶代理外的其他HTTP頭都影響著檢測結果。對Opera Mini和Opera 移動瀏覽器來說尤其是這樣的。在這兩個瀏覽器里,第二個HTTP頭,也就是名字為Device-Stock-UA的頭常常用來提供標準用戶代理里沒有的有 關物理硬件的信息。
為什么監控?
監控使得我們能夠將不受歡迎的內容從主頁中刪除,以此提升更重要的內容或相關的內容的性能。刪除的內容應該仍可以通過二級頁面訪問到——只是不放在首頁,不然的話它們會消耗寶貴的帶寬并降低性能體驗。
那么,我們怎樣來創建一個獨立的性能優化的移動網站呢?
分而治之
我能理解為什么RWD(響應web設計)從用戶界面設計的角度來說很有意義。對于6平方英寸屏幕和10平方英寸屏幕,以及僅僅是需要進行改動的布局來說,在內容,導航以及業務流程需求方面可以完全一致,這實在是太棒了。
平均設備屏幕尺寸。
但是,在上述條件不為真或者對性能要求嚴格的時候有一個獨立的移動網站 具有特別的意義。
獨立的移動網站常常表現出一種不良的用戶體驗。通過給網站懲罰賦以較低的搜索引擎等級,Google現在投射出一縷曙光 到這些普通的問題上。問題包括了將每個桌面頁發送到單獨的移動主頁,重定向到應用下載頁,阻止用戶訪問大屏的網站,對所有帶特定操作系統的設備以相同的方式處理。
這些糟糕的實現讓人對這些概念有一個壞的印象。這里是一些簡單又正確的做法。
下面的 .NETweb.config片段將把來自智能手機的第一個請求,重定向到網站上“Smartphone”部分指定的等價頁面。 重要的是,查詢字符串與頁面名字在重定向的過程中一直保持著。
- <redirect firstRequestOnly="true"
- mobileHomePageUrl="~/Mobile/Default.aspx"
- timeout="20"
- devicesFile="~/App_Data/Devices.dat"
- mobilePagesRegex="/(Mobile|Smartphone)/" >
- <locations>
- <!--Send smartphones to an equivalent version of the original page, preserving the page name and query string.-->
- <location name="smartphone" url="~/Smartphone/{0}" matchExpression="(?<=^\w+://.+/).+">
- <add property="IsSmartphone" matchExpression="true"/>
- </location>
- </locations>
- </redirect>
在大多數情形,當重定向到替代頁面時,如果愿意的話用戶應當可以返回原始的頁面; 或許他們對網站的大屏幕版本更熟悉呢。firstRequestOnly屬性保證了只有來自設備的第一次請求才被重定向。devicesFile屬性是用 來對不支持cookies的設備進行跟蹤。timeout屬性控制了在多長時間內該設備被記憶(為了重定向的目的)。
重定向系統還必須知道哪個頁面是針對哪種設備設計的。mobilePagesRegex屬性被應用到請求URLs。如果存在匹配,頁面將不適用重定向。這阻止了無窮重定向的情況。
locations元素允許配置定義不同的地址,以及相關的規則。這個例子將Smartphone目錄插入到原始的URL。查詢字符串和其他的URL信息在重定向過程中一直保持。所有影響到請求上下文的信息必須被傳送,以便用戶獲得他們期望的內容。
這個簡單的方法使得一個搜索引擎友好的,兼容Google的,移動手機優化的網站,在傳送的過程中有良好的用戶體驗和優異的性能。這個過程的基礎是DDR,它快速的,一致的,精確的提供了設備的信息。對于改變了移動手機瀏覽器設置到桌面模式的用戶,重定向將不會發生。
警惕云
云服務是給網站迅速增加特性的流行方法。但是它們跨越Internet的請求對性能帶來損耗。如果忽略處理時間,我們觀察到由Amazon Web Service提供的云服務的數據傳輸有平均200毫秒的延時。
200毫秒是一個黃金秒的20%。因此,仔細考慮一下你使用的云服務在哪里,確保它們是異步調用的,以便在等待響應的過程中其他處理能繼續下去。它們應該避免關鍵路徑上的活動,例如判別請求設備的信息。