Nginx學習:WebDav文件存儲與圖片媒體處理模塊
今天的內容怎么說呢?有兩個感覺非常有意思,另外一些就差點意思。有意思的是,咱們可以直接用 Nginx 的 Webdav 功能搭建一個網盤,另外也可以實現動態的圖片處理。這兩個功能吧,有其局限性,但也非常方便。另外的流媒體部分的內容,主要 FLV 和 MP4 這兩種視頻媒體格式的處理,說實話,沒啥實際的內容,了解一下就好了。
WebDav
關于 WebDav 是干嘛的,大家可以自己去百度一下。沒學之前我也不知道這是個什么東西,我們學習,其實往往都是通過某一個點而延伸到其它方面的。比如說學習 Nginx ,一直強調的就是要有網絡的基礎。然后基于網絡能干什么事呢?那可就太多了,Web 應用服務器只是 Nginx 其中的一個功能,而一個簡單的基于 HTTP 的網盤,就只是它提供的一個核心功能中的小功能而已。
這個功能模塊的命名是 ngx_http_dav_module ,它不是核心源碼中的,所以是需要我們在編譯的時候選裝的。不過,在實際測試并且查詢相關資料之后,發現原生的模塊是有坑的,還需要再多裝一個第三方模塊才能更好地使用這個功能。在這里也不賣關子,先告訴大家要安裝什么,怎么安裝,然后再看每個指令,最后測試的時候再說到底為啥需要多裝一個第三方模塊。
首先我們要下載這個模塊,直接 Github 去下載就好了,放在哪里都可以。
[root@localhost?~]#?git?clone?https://github.com/arut/nginx-dav-ext-module.git
然后就是去源碼包中進行編譯安裝,使用?--add-module
?添加第三方模塊。
[root@localhost?nginx-1.23.0]#?./configure?……………………?--with-http_dav_module?--add-module=/root/nginx-dav-ext-module/
[root@localhost?nginx-1.23.0]#?make?&&?make?install
安裝完成之后就可以使用了,我們先來看看 WebDav 模塊中的配置指令有哪些,它們都可以配置在 http、server、location 模塊下。
create_full_put_path
允許創建所有需要的中間目錄。
create_full_put_path?on?|?off;
默認值是 off ,其實只要改成 on 的話,我們就可以自己創建新的文件夾,因為 WebDAV 規范只允許在已經存在的目錄中創建文件。
dav_access
為新創建的文件和目錄設置訪問權限。
dav_access?users:permissions?...;
默認值是 user:rw 。意思就是用戶可以有讀寫權限,這個其實和 Linux 的用戶權限比較類似。不過一般我們操作的 WebDav 目錄都會設置成和 Nginx 中的 user 配置指令一樣的用戶及用戶組,比如我這里就是 www 用戶和用戶組,那么就是對于 www 用戶來說的權限。如果指定了任何組或所有訪問權限,則可以省略用戶權限,比如直接設置?group:rw all:r;
?就可以了。
dav_methods
允許指定的 HTTP 和 WebDAV 方法。
dav_methods?off?|?method?...;
默認值是 off ,表示拒絕所有的方法。這里的方法是什么意思呢?和我們 HTTP 中的 Method 是一樣的,但是 WebDav 的方法不是完全一樣的。比如它支持配置的有:PUT、DELETE、MKCOL、COPY 和 MOVE。
從名字可以看出,PUT 是上傳文件,它會被寫入到臨時文件中,然后文件被重命名。DELETE 就是刪除,MKCOL 是創建文件夾,COPY 是復制,MOVE 就是移動啦。貌似和 RESTFul 有點像啊,一種方法代表一種意思。
從版本 0.8.9 開始,臨時文件和持久存儲可以放在不同的文件系統上。但是,請注意,在這種情況下,文件是跨兩個文件系統復制的,而不是廉價的重命名操作。因此,建議對于任何給定位置,保存的文件和保存臨時文件的目錄(由 client_body_temp_path 指令設置)放在同一個文件系統上。 使用 PUT 方法創建文件時,可以通過在“Date”標頭字段中傳遞修改日期來指定修改日期。
注意,要使用第三方模塊的坑就在這里,一會我們就會說到。
min_delete_depth
允許 DELETE 方法刪除文件,前提是請求路徑中的元素數量不少于指定數量。
min_delete_depth?number;
默認值是 0 ,一般不太需要設置這個配置,為啥呢?假如,配置這個選項為?min_delete_depth 4
?那么允許刪除請求中的文件路徑是這樣的
/users/00/00/name
/users/00/00/name/pic.jpg
/users/00/00/page.html
而下面這種是不能刪除的。
/users/00/00
是的,就是說只能刪除幾層目錄。0 就表示一層就可以刪,這是比較符合我們日常的習慣的。
WebDav 測試
就四個配置指令,不多吧,但是我們在實際的配置中還會用到其它的一些配置。
location?/webdav/?{root??????????????????/usr/local/nginx/html;autoindex?on;client_body_temp_path?/tmp;dav_methods?PUT?DELETE?MKCOL?COPY?MOVE;dav_ext_methods?PROPFIND?OPTIONS?LOCK?UNLOCK;?#?DAV擴展支持的請求方法create_full_put_path??on;dav_access????????????group:rw??all:r;auth_basic?"webdav";auth_basic_user_file?/etc/nginx/conf/htpasswd;#limit_except?GET?{#????allow?192.168.56.0/32;#????#deny??all;#}
}
上面的配置中,我們為 /webdav/ 這個目錄設置一個 location ,注意,目錄要創建好哦,要不和普通頁面一樣會一直 403 的。然后就是我們學過的 root、autoindex、client_body_temp_path ,不用多解釋了吧,autoindex 上篇文章剛學,主要是為了展示我們用瀏覽器也可以看到文件變化。
接著,我們就配置了 dav_methods 和 dav_ext_methods 兩個指令。dav_ext_methods 是啥?它正是我們所安裝的第三方模塊中帶的配置指令。默認情況下,自帶的 ngx_http_dav_module 模塊中,dav_methods 只能設置上面說的那五個指令,但是在我的實際測試中,比如使用 Mac 訪達的【前往】->【連接服務器】進行連接時,會發送下面這樣一請求。
192.168.56.1?-?-?[17/Aug/2022:20:46:19?-0400]?"OPTIONS?/webdav/?HTTP/1.1"?405?157?"-"?"WebDAVLib/1.3"
注意,它的請求方法是 OPTIONS ,不在自帶的那五個方法之中。因此,我們需要擴展模塊來實現對一些擴展方法的支持,否則,這個請求就會一直返回 405 狀態,客戶端自然也就連不上。
接下來,設置 create_full_put_path 為 on ,設置權限為?group:rw all:r;
?,基本就是常規的全給權限的操作了。
再往下,又是我們前面學過的訪問認證的兩個命令,使用的也是之前我們設置過的用戶名和密碼文件。
好了,使用 Mac 的話你就可以使用 Finder 的 【前往】->【連接服務器】來試試連接了,要輸入用戶名或密碼的話直接輸入 auth_basic 中有的用戶名和密碼就可以了。如果你是 Windows 電腦,也是一樣在通過文件夾中的遠程訪問工具就可以打開了。
不過,使用這些操作系統原生的文件系統工具,你會發現一個問題,那就是我們沒辦法創建文件或目錄,也沒辦法拖一個進去。這主要是因為它們不支持上面那五個完整的 WebDav 方法。所以我們需要去安裝一些支持 WebDav 的工具,比如我在 Mac 的應用商店中找到的一個免費的 FE File Explorer 軟件,直接安裝后,選擇創建一個新的 WebDav 連接,然后填入 URL 地址以及帳號密碼就可以操作了。
好了。現在這個網盤已經可以使用了。不過大家也可以試一下,如果不用 auth_basic 會怎么樣?注釋掉那兩行并重載 Nginx 的話,咱們其實還可以使用 Linux 的用戶登錄,比如我這里只有 root 用戶,那么我們就可以用 root 的帳號和密碼進行登錄,一樣的可以進行文件操作。
另外,在這個 location 中,還可以通過之前學過的 limit_except 指令來進行訪問限制,這樣如果真是的在外網暴露出來當做網盤的話,也可以更進一步地增加安全性。同時,還可以配置 https 來通過 https 進行連接傳輸。
不過話說回來,真正要弄一個自己個人的網盤的話,還是買個大的硬盤和一個好點的路由或者直接買個家庭NAS,畢竟電腦搭一個還費更多的電呢~
空圖片 empty_gif
空圖片?這又是啥?其實呀,并不是一個完全的空圖片,而是一個只有 1 個像素的,并且這個像素還是透明的一張 GIF 圖片。
location?/emptygif/?{empty_gif;
}
試試訪問 /emptygif/ 或者這個路徑下的任意子路徑或文件,返回的都是一個啥也看不到的 GIF 圖片,使用下載工具的還能下載下來,并且真的是一張圖片。
那么,要這個東西干嘛呢?如果你接觸過大數據技術的話,其中有一種埋點上報方式就是前端直接請求一個類似于這種形式的空圖片,然后將埋點數據帶到 GET 參數中。大數據相關的工具直接分析 Nginx 的 access_log ,提取其中的 GET 參數進行數據分析。
有一個最典型的例子,就是百度統計。
看到沒有,大家從百度統計中獲取到的那段統計代碼,會加載一個 hm.js 的遠程 JS 文件并運行里面的代碼。然后在這個文件中,會收集客戶端瀏覽器的很多信息,并拼接成 GET 參數,最后再使用這些參數請求一下 hm.gif 這個 empty gif 圖片。
這么做有什么好處呢?這是一種純靜態,不需要數據庫,可以支撐超高并發量的收集數據的一種方式。雖說百度的這張圖片返回的響應頭顯示的服務器是 Apache 吧,但用 Nginx 也是一樣的。我們不需要后端程序,也不用將這一堆參數放到數據庫,甚至連緩存都不用,就直接使用 Apache 或者 Nginx 自帶的這種訪問日志的功能,就可以收集到這些海量的請求數據了。要知道,普通單臺 Nginx 的并發量最差最差的配置都是可以達到幾萬級別的。
empty_gif
返回一個透明像素的GIF圖片。
empty_gif;
沒有配置值,也不需要配置值,只能配置在 location 下面。
圖片過濾 ImageFilter
還記得之前我們在 PHP 的文章和視頻中學過的 GD 庫、ImageMagick 和 GMagick 這些內容嘛?如果不記得的小伙伴就去公眾號或者我的博客搜索哈,也有對應的標簽可以快速地找到。
沒錯,圖片過濾模塊就是可以像上面說那些 PHP 中的功能一樣,方便快捷地對圖片進行一些簡單的處理。功能沒有動態語言的強大,但是提供的配置指令說實話也夠用了。它的全名是 ngx_http_image_filter_module ,需要獨立安裝,在 configure 中添加 --with-http_image_filter_module 就可以了。此外,它還需要操作系統中有 libgd 庫的支持,因此,我們還需要安裝 GD 庫組件。
yum?install?gd?gd-devel
這一個模塊,我們根據配置指令的說明,同步地一個一個地測試。除了 image_filter 只能配置在 location 下之外,其它的都可以配置在 http、server、location 中。在此之前,我們還需要準備好一個 img 目錄和圖片文件。
原始的圖片文件是這樣的。
image_filter
設置圖像變換的操作。
image_filter?off;
image_filter?test;
image_filter?size;
image_filter?rotate?90?|?180?|?270;
image_filter?resize?width?height;
image_filter?crop?width?height;
好多配置選項呀,默認是 off 也就是關閉的。它決定了后面我們其它的指令是否可用,也就是說,如果是 off 狀態,那么其它相關的配置指令也都不會起作用。
在這些配置參數中,test 和 size 是單獨使用的,后面三個可以配合使用。這是啥意思?先看解釋,最后再說。
test 確保應答是 JPEG ,GIF 或 PNG 格式的圖像。否則錯誤 415 (Unsupported Media Type) 將被返回。
location?/img/?{#image_filter?test;
}
如果正常訪問上面的路徑,我們可以打開 index.html ,本身這就是一個正常的 html 頁面嘛。但是如果開啟上面的注釋,再次訪問 index.html ,就會發現返回 415 錯誤了。
size 以JSON格式返回圖像信息。
location?/img3/{alias?/usr/local/nginx/html/img/;image_filter?size;
}
訪問 /img3/1.jpeg 和 /img3/2.jepg 會返回這樣的內容。
http://192.168.56.88/img3/1.jpeg
{"img":?{"width":?1920,"height":?1200,"type":?"jpeg"}
}//?http://192.168.56.88/img3/2.jpeg
{"img":?{"width":?4878,"height":?3215,"type":?"jpeg"}
}
rotate 將圖像逆時針旋轉指定角度,參數的值可以包含變量。可以單獨使用,或與 resize 和 crop 變換同時使用。
resize width height 按比例縮小圖像至指定大小。 如果想只指定其中一維,另一維可以指定為: - 。 如果有錯誤發生,服務器會返回 415 (Unsupported Media Type). 參數的值可以包含變量。 當與 rotate 參數同時使用時, 旋轉發生在縮放之后。
location?/img1/?{alias?/usr/local/nginx/html/img/;image_filter?resize?300?300;image_filter?rotate?90;error_page?415??/emptygif/;error_page?404??/emptygif/;
}
我們直接測試 rotate 和 resize ,注意,rotate 是只能和 resize 或 crop 之一配合。它是旋轉,另外兩個都是改變大小。在這個配置中,我們會對圖片進行等比例縮放,注意,并不是圖片直接變成 300*300 而是根據長寬大小,選擇合適的長或寬,縮放到長寬都不超 300 的界限。這兩個值也可以設置成不一樣的,以小的為準。看看圖片的效果是啥樣。
是不是有點意思了,有 ImageMagick 的感覺了吧。另外在這個路徑的配置中,我們還加入了 error_page ,讓 415 和 404 的錯誤都指向上一小節學習到的 empty_gif 模塊中,這樣就不會出現前面的 415 錯誤頁面啦。
crop width height 按比例以圖像的最短邊為準對圖像大小進行縮小,然后裁剪另一邊多出來的部分。 如果想只指定其中一維,另一維可以指定為: - 。 如果有錯誤發生,服務器會返回 415 (Unsupported Media Type). 參數的值可以包含變量。 當與?
rotate
?參數同時使用時, 旋轉發生在裁剪之前。location?/img2/?{alias?/usr/local/nginx/html/img/;image_filter?crop?500?300;#image_filter_jpeg_quality?95;#image_filter_sharpen?10; }
注意,這個是裁剪了,指定的寬高是多少,裁剪出來的圖片大小就是多少了。下面注釋的指令我們馬上就講。
對于后面三個參數來說,如果你在有這三個參數的 location 中同時加入了 test 或者 size ,它們的縮放、旋轉、裁剪效果馬上就無效了。大家可以自己試試哦,這就是前面說的不兼容的問題。另外 crop 和 resize 放一起會是什么效果呢?會以最后設置的為準。
image_filter_buffer
設置用來讀圖像的緩沖區的最大值。
image_filter_buffer?size;
默認值是 1M ,訪問我們上面第二張圖片 2.jpeg ,它的大小超過 1M 了,正常情況下會返回 415 錯誤,這時我們就可以設置 image_filter_buffer ,調大之后就可以訪問了,我們可以將它放在 http 或者 server 下面,這樣我們上面測試的那些路徑就都可以打開第二張圖片了。
image_filter_interlace
啟用圖像隔行掃描的。
image_filter_interlace?on?|?off;
默認值是 off ,只對 JPG 圖片有效果。這個其實我們原來也說過,就是 JPG 圖片在網頁呈現有兩種方式,一個是一行一行的出現,一個是先模糊后清晰的。這個在 PhotoShop 導出 Web 格式圖片時可以設置。不過我這里沒裝,所以也不多做演示了。直接配置針對我從網上找到的這兩張圖片也沒啥效果。
image_filter_jpeg_quality
設置變換后的JPEG圖像的質量。
image_filter_jpeg_quality?quality;
默認值是 75 ,在上面 crop 的設置中有注釋,大家可以打開,設置成 1 看看效果就明白什么意思了。大家應該了解過,JPG 是壓縮格式的圖片,我們在 PhotoShop 導出時也可以對 JPG 格式圖片設置壓縮比,這個值越小,圖片越小,但越不清楚。這個值越大,圖片大小也越大,圖片也越清楚。它只對 JPG 圖片有效果,并且是 resize、rotate、crop 操作之后的 JPG 圖片,其它格式無效。
image_filter_sharpen
增加最終圖像的清晰度。
image_filter_sharpen?percent;
默認值是 0 ,也就是不做操作。其實就是圖形工具中的銳化工具,同樣可以在上面 crop 中打開注釋進行測試,和 image_filter_jpeg_quality 的要求一樣,不過可以不只是 JPG 圖片。
image_filter_transparency
定義當對PNG,或者GIF圖像進行顏色變換時是否需要保留透明度。
image_filter_transparency?on|off;
默認值是 on ,損失透明度有可能可以獲得更高的圖像質量,PNG圖像中的alpha通道的透明度默認會一直被保留。我沒有測試,大家可以自己試試哈。
image_filter_webp_quality
設置轉換后的 WebP 圖像的所需質量。
image_filter_webp_quality?quality;
和 image_filter_jpeg_quality 類似,只不過它針對的是 WebP 格式的圖片。這種圖片格式現在也比較流行了,可接受的值在 1 到 100 的范圍內。較小的值通常意味著較低的圖像質量和較少的數據傳輸。參數值可以包含變量。
一個好玩的小例子
最后,我們再來做一個小例子。很多云存儲比如 阿里云的OSS、七牛云、UpYun 的存儲功能中,都有一項是可以動態改變圖片的大小,比如等比例縮放或裁剪等,只需要我們在請求圖片的 URL 后面加上參數就可以,比如說七牛是類似于這樣的鏈接:http://xxxx/1.jpg?imageView2/1/w/200/h/200。大部分情況下,如果我們自己實現,可以借助 PHP 配合 ImageMagicK 來達到同樣的效果。但是在學完上面的內容之后,大家是不是馬上就想到了,通過 Nginx 也可以實現呀。
location?/img4/?{alias?/usr/local/nginx/html/img/;if?($arg_w?=?"")?{set?$arg_w?'-';}if?($arg_h?=?"")?{set?$arg_h?'-';}image_filter?resize?$arg_w?$arg_h;image_filter_jpeg_quality?95;
}
直接將 resize 的值設置成變量就可以啦。現在訪問 /img4/1.jepg ,然后加上參數 ?w=400&h=150 看看效果吧。是不是很有意思,像這樣簡單的處理,其實都不需要我們單獨去安裝 ImageMagicK 以及相應的 PHP 擴展了。
FLV 文件
ngx_http_flv_module 模塊,為Flash Video(FLV)文件 提供服務端偽流媒體支持。這個模塊需要 --with-http_flv_module 編譯安裝,不是核心源碼中的。
FLV
為Flash Video(FLV)文件 提供服務端偽流媒體支持。
flv;
通過返回以請求偏移位置開始的文件內容,該模塊專門處理在查詢串中有 start 參數的請求, 和有預先設置到FLV頭部的請求。只能在 location 中設置。
不知道咋測試,所以大家了解一下就好了。
MP4 文件
和上面那個 FLV 的模塊是一樣的,全名是 ngx_http_mp4_module 模塊。為H.264/AAC文件,主要是以?.mp4
、.m4v
、和.m4a
為擴展名的文件, 提供偽流媒體服務端支持。
偽流媒體是與Flash播放器一起配合使用的。 播放器向服務端發送HTTP請求,請求中的查詢串是以開始時間為參數的(以?start
簡單命名),而服務端以流響應,這樣流的開始位置就能與請求中的時間相對應。 例如:
http://example.com/elephants_dream.mp4?start=238.88
這樣就允許隨意拖放,或者從節目的中途開始回放。
為了支持隨機訪問,H.264格式將元數據放到所謂的"moov atom"中。 "moov atom"是文件的一部分,放有整個文件的索引信息。
為了開啟回放,播放器首先需要讀取元數據。 這是通過發送一個特別的以start=0
為 參數請求來完成的。 許多編碼軟件會將元數據插入到文件末尾, 這樣做對偽流媒體來說是不好的: 元數據需要在文件開始時定位好,否則整個文件需要下載完才能開始播放。 如果文件組織的很好(將元數據放到文件開頭),那么nginx僅僅返回文件的內容, 否則,nginx不得不讀取文件并準備一個新的流,將元數據放在媒體數據前面, 這將導致一些CPU,內存,磁盤I/O開銷。 所以一個比較好的主意是為偽流媒體準備文件 , 而不是讓nginx處理請求時做。
對于匹配有非零?start
?參數的請求,nginx從文件中讀取元數據,從請求的偏移位置開始準備流數據發送給客戶端。 這與上面描述的情況有同樣的開銷。
如果匹配的請求沒有包含?start
?參數,就不會有額外開銷,而文件僅僅是以靜態資源被發送。 一些播放器也支持字節范圍請求,所以就根本不需要這個模塊。
這個模塊默認是不安裝的,需要通過 --with-http_mp4_module 來配置開啟。
mp4
配置開啟該模塊處理當前路徑。
mp4;
只能定義在 location 當中。
mp4_buffer_size
設置處理MP4文件的初始內存大小。
mp4_buffer_size?size;
默認值是 512K 。
mp4_max_buffer_size
在處理元數據時,可能必需較大的緩存。 它的大小不能超過 size 指定的值, 否則 Nginx 將會返回服務器錯誤。
mp4_max_buffer_size?size;
默認值是 10M ,返回的是 500 錯誤,并記錄日志,日志格式是這樣的:
"/some/movie/file.mp4"?mp4?moov?atom?is?too?large:?12583268,?you?may?want?to?increase?mp4_max_buffer_size"
總結
怎么樣,WebDav 和 ImageFilter 功能都是非常有意思的吧。流媒體這一塊的確實是不知道要怎么測試。因此,也就沒有更加詳細的介紹了。如果有了解的小伙伴也希望評論留言一起學習哦。
下篇文章開始,我們要學習一個非常重要的子模塊,那就是 FastCGI 相關的模塊配置。
參考文檔:
http://nginx.org/en/docs/http/ngx_http_dav_module.html
http://nginx.org/en/docs/http/ngx_http_empty_gif_module.html
http://nginx.org/en/docs/http/ngx_http_image_filter_module.html
http://nginx.org/en/docs/http/ngx_http_flv_module.html
http://nginx.org/en/docs/http/ngx_http_mp4_module.html