使用阿里云OSS+CDN部署前端頁面與加速靜態(tài)資源

本文不再更新,新的更新內(nèi)容一律放原文鏈接

前言

直到今天我見過很多網(wǎng)站還是傾向使用獨(dú)立的服務(wù)器部署自己的網(wǎng)站。但是在云服務(wù)更加完善的今天,已經(jīng)有更好的選擇。本文將介紹使用阿里云的OSS+CDN部署自己的前端頁面,以及加速靜態(tài)資源。

直接使用阿里云的OSS+CDN的方案有幾大好處:

  • 成本低廉。OSS+CDN部署自己的網(wǎng)站每個(gè)月的花費(fèi)遠(yuǎn)比自己買ECS服務(wù)器部署網(wǎng)站花費(fèi)要少得多
  • 大幅降低運(yùn)維成本。直接使用現(xiàn)成的云服務(wù)了,無需花精力去維護(hù)ECS了。
  • 極高的可用性。無論阿里云的OSS還是CDN,都已經(jīng)做好了高可用性,幾乎可以保證網(wǎng)站始終可訪問
  • 極高的訪問速度。ECS帶寬畢竟有限的,高帶寬意味著超高的費(fèi)用。但是用OSS+CDN這種天然分布式的架構(gòu)部署網(wǎng)站很輕松的解決了帶寬問題,極大地提升了用戶的訪問體驗(yàn)。

部署準(zhǔn)備

  • 備案過的域名
  • 足夠的余額(流量不大的話100元余額都?jí)蛴煤脦讉€(gè)月,比ECS便宜得多)

阿里云CDN需要綁定自己的域名,國內(nèi)要求必須備案,所以務(wù)必先備案自己的域名。如果這個(gè)域名在阿里云購買的更好,幾乎可以做到不用手改域名解析記錄,阿里云會(huì)自動(dòng)處理。

OSS和CDN都是后付費(fèi)的服務(wù),因此需要保證賬戶有足夠的余額。價(jià)格方案: https://cn.aliyun.com/price/product#/oss/detail

注意: 網(wǎng)站鏈接需要特別注意,阿里云OSS的網(wǎng)站托管是兼容Angular的路由的,也就是根目錄只有一個(gè)index.html,其他目錄的訪問都應(yīng)該rewrite到/index.html。所以如果你的靜態(tài)資源不是通過Angular build出來的,不應(yīng)該使用/location/這種路徑頁面跳轉(zhuǎn),應(yīng)該使用/location/index.html這種路徑,否則訪問/location/將顯示/index.html中的內(nèi)容。

具體的細(xì)則請(qǐng)參考阿里云的官方文檔: 配置靜態(tài)網(wǎng)站托管

部署步驟

開通OSS與CDN服務(wù)

這兩個(gè)服務(wù)都是按量付費(fèi)的,開通是不需要費(fèi)用的。

OSS創(chuàng)建bucket

每個(gè)獨(dú)立的bucket可以當(dāng)做一個(gè)獨(dú)立的網(wǎng)盤對(duì)待,要求bucket name全局唯一,不能重名。創(chuàng)建一個(gè)前端托管的bucket參考配置如下:

image.png

配置bucket

bucket創(chuàng)建之后,默認(rèn)的bucket配置是不具有靜態(tài)網(wǎng)站托管的功能的,因此需要做一些配置。參考配置如下:

image.png

啟用CDN加速

OSS目前的策略限制了不能通過OSS自己的域名直接打開index.html,會(huì)變成下載。因此無論是否使用CDN,都必須綁定自己的域名。由于啟用CDN之后會(huì)加速OSS,并且回源流量半價(jià),還是挺劃算的,因此建議啟用CDN。啟用CDN的辦法如下:

image.png
image.png

稍等片刻之后,等待CDN配置之后,轉(zhuǎn)到CDN控制臺(tái)就可以看到這個(gè)域名了:

image.png

此時(shí)基本配置就已經(jīng)結(jié)束了,之后你可以上傳你的靜態(tài)網(wǎng)站到這個(gè)bucket的根目錄下了。不過在此之前可以做一些CDN的優(yōu)化配置

CDN的一些優(yōu)化配置(可選)

CDN支持定制HTTP響應(yīng)頭的功能,一個(gè)比較常見的設(shè)置是直接在http頭中添加瀏覽器緩存的頭(cache-control),這個(gè)功能可以在緩存配置這里直接配置緩存規(guī)則:

image.png

目前全站https已經(jīng)是趨勢(shì)了而且免費(fèi)的證書服務(wù)目前也比較多了。阿里云CDN就支持申請(qǐng)DigiCert免費(fèi)證書,并且自動(dòng)續(xù)期。下面的HTTP/2也建議啟用:

image.png
image.png

上面的DigiCert免費(fèi)證書申請(qǐng)需要特別注意,如果你的主機(jī)頭是www,必須將空主機(jī)頭@CNAME也解析到CDN上才能申請(qǐng)成功。

此外,性能優(yōu)化個(gè)人建議全部勾選,可以減少部分帶寬:

image.png
image.png

上傳/更新網(wǎng)站

到此為止OSS+CDN的部分已經(jīng)配置完畢了,只要把靜態(tài)頁面上傳到OSS上就搞定了。建議通過oss客戶端上傳,可以支持批量拖拽上傳,而不是在OSS控制臺(tái)上一個(gè)一個(gè)上傳。

這里我推薦阿里云官方的開源項(xiàng)目oss-browser,因?yàn)檫@個(gè)客戶端可以跨平臺(tái),并且支持記錄AK,使用上很方便。

使用前需要開啟賬戶的AccessKey,或者專門創(chuàng)建一個(gè)低權(quán)限的子賬戶管理OSS。

image.png

每次更新網(wǎng)站的時(shí)候,可能需要手工刷新下CDN(盡管OSS配置中有個(gè)自動(dòng)刷新CDN的功能,但我發(fā)現(xiàn)使用客戶端是上傳的時(shí)候無效。疑似通過API上傳的文件不會(huì)觸發(fā)CDN刷新)。進(jìn)入CDN的控制臺(tái),點(diǎn)擊刷新,輸入一下要刷新的URL路徑即可:

image.png

這里分享一下我個(gè)人的deploy.sh腳本,拼接阿里云接口參數(shù)的函數(shù)部分改動(dòng)自acem.sh這個(gè)項(xiàng)目,在此之上做了一些擴(kuò)充,感謝貢獻(xiàn)者:

#!/bin/bash -e

_urlencode() {
  # urlencode <string>
  old_lc_collate=$LC_COLLATE
  LC_COLLATE=C
  length="${#1}"
  for (( i = 0; i < length; i++ )); do
    local c="${1:i:1}"
    case $c in
      [a-zA-Z0-9.~_-]) printf "$c" ;;
    *) printf '%%%02X' "'$c" ;;
    esac
  done
  LC_COLLATE=$old_lc_collate
}

_ali_nonce() {
    date +"%s%N"
}

_timestamp() {
    date -u +"%Y-%m-%dT%H%%3A%M%%3A%SZ"
}

_ali_urlencode() {
    _str="$1"
    _str_len=${#_str}
    _u_i=1
    while [ "$_u_i" -le "$_str_len" ]; do
        _str_c="$(printf "%s" "$_str" | cut -c "$_u_i")"
        case $_str_c in [a-zA-Z0-9.~_-])
            printf "%s" "$_str_c"
            ;;
        *)
            printf "%%%02X" "'$_str_c"
            ;;
        esac
        _u_i="$(($_u_i + 1))"
    done
}

_ali_signature() {
    sorted_query=$(printf "%s" "${query}" | tr '&' '\n' | sort | paste -s -d '&')
    string_to_sign=$(printf "%s" "GET&%2F&$(_ali_urlencode "${sorted_query}")")
    signature=$(printf "%s" "${string_to_sign}" | openssl sha1 -binary -hmac "${ACCESS_KEY_SECRET}&" | base64)

    _ali_urlencode "${signature}"
}

aliyun_request_builder() {
    query="Format=json&AccessKeyId=${ACCESS_KEY_ID}&SignatureMethod=HMAC-SHA1&SignatureVersion=1.0&Version=${version}"
    query="${query}&SignatureNonce=$(_ali_nonce)&Timestamp=$(_timestamp)"

    for q in "$@"; do
        query="${query}&${q%%=*}=$(_ali_urlencode "${q#*=}")"
    done

    query="${query}&Signature=$(_ali_signature "${query}")"
    echo "${query}"
}

aliyun_rest() {
    query="${1}"
    curl -fs "${aliyun_endpoint}?${query}"
}

aliyun_cdn_refresh() {
    ACCESS_KEY_ID="${CDN_ACCESS_KEY_ID}"
    ACCESS_KEY_SECRET="${CDN_ACCESS_KEY_SECRET}"
    if [ -z "${ACCESS_KEY_ID}" ] && [ -z "${ACCESS_KEY_SECRTE}" ]; then
        echo "請(qǐng)?jiān)O(shè)置CDN_ACCESS_KEY_ID,CDN_ACCESS_KEY_SECRET環(huán)境變量"
        exit 1
    fi

    aliyun_endpoint="https://cdn.aliyuncs.com/"
    version="2014-11-11"
    request_query="$(aliyun_request_builder \
        Action=RefreshObjectCaches \
        "ObjectPath=${1}" \
        ObjectType=File)"

    aliyun_rest "${request_query}"
}

_oss_upload_one_file() {
    file="${1}"
    if [ -z "${OSS_ACCESS_KEY_ID}" ] && [ -z "${OSS_ACCESS_KEY_SECRET}" ] && [ -z "${OSS_BUCKET}" ]; then
        echo "請(qǐng)?jiān)O(shè)置OSS_ACCESS_KEY_ID, OSS_ACCESS_KEY_SECRET, OSS_BUCKET三個(gè)環(huán)境變量"
        exit 1
    fi
    upload_path="${OSS_BASE_PATH:-/}"
    host="${OSS_BUCKET}.oss-cn-hangzhou.aliyuncs.com"
    Date="$(LC_ALL=C TZ=GMT date +'%a, %d %b %Y %T %Z')"
    Content_MD5=`openssl md5 -binary < "${file}" | base64`
    extension="${file##*.}"

    case "${extension,,}" in
        js)
            Content_Type=application/javascript
            ;;
        css)
            Content_Type=text/css
            ;;
        json)
            Content_Type=application/json
            ;;
        woff)
            Content_Type=font/woff
            ;;
        woff2)
            Content_Type=font/woff2
            ;;
        *)
            Content_Type=$(file -b --mime-type "${file}")
            ;;
    esac

    storage_path="${upload_path}${file}"
    CanonicalizedResource="/${OSS_BUCKET}${storage_path}"
    SignString="PUT\n${Content_MD5}\n${Content_Type}\n${Date}\n${CanonicalizedResource}"
    Signature=`echo -ne "$SignString" | openssl sha1 -binary -hmac "${OSS_ACCESS_KEY_SECRET}" | base64`
    Authorization="OSS ${OSS_ACCESS_KEY_ID}:${Signature}"

    echo "Uploading '${file}' to bucket: '${OSS_BUCKET}' path: '${storage_path}', content-type: '${Content_Type}'"
    curl -XPUT -sfLkT "${file}" \
        -H "Content-Type: ${Content_Type}" \
        -H "Date: ${Date}" -H "Content-Md5: ${Content_MD5}" \
        -H "Authorization: ${Authorization}" "https://${host}${storage_path}"
}

export -f _oss_upload_one_file

oss_upload() {
    src="${1}"
    cd "${src}"
    find -type f -printf "%P\0" | xargs -0 -I{} --no-run-if-empty -P10 bash -ec "_oss_upload_one_file {}"
}

main() {
    oss_upload "${1}"

    if [ -n "${CDN_URL}" ]; then
        echo "Refreshing CDN: '${CDN_URL}'"
        aliyun_cdn_refresh "${CDN_URL}"
    fi
}

main

AK信息配置到環(huán)境變量中:

export OSS_ACCESS_KEY_ID=xxxxxxx
export OSS_ACCESS_KEY_SECRET=xxxxxxx
export OSS_BUCKET=your-bucket
# 如果沒有啟用阿里云的CDN,下面三個(gè)環(huán)境變量可以不賦值
export CDN_URL=https://www.domain.com/  # 阿里云的CDN刷新地址要求路徑最后的/不能省略
export CDN_ACCESS_KEY_ID=xxxxxxx
export CDN_ACCESS_KEY_SECRET=xxxxxxx

./deploy.sh /path/to/website/

注意點(diǎn):

  • 使用的oss endpoint為杭州節(jié)點(diǎn),其他節(jié)點(diǎn)可以自行修改host="${OSS_BUCKET}.oss-cn-hangzhou.aliyuncs.com"這一行
  • 考慮到OSS和CDN可能會(huì)分成兩個(gè)子賬戶管理,因此將OSS和CDN的賬戶AK信息分成兩組環(huán)境變量存儲(chǔ)
  • 如果CDN_URL不存在,則不會(huì)在上傳后自動(dòng)刷新CDN路徑
  • 刷新CDN方案使用的刷新類型是URL,上述配置只刷新了/這一個(gè)訪問地址。因此期望整個(gè)網(wǎng)站使用CDN友好(即每次更新資源之后,文件名或引用路徑會(huì)改變,比如Angular或Vue的產(chǎn)品環(huán)境編譯)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,702評(píng)論 6 534
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,615評(píng)論 3 419
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,606評(píng)論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,044評(píng)論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,826評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,227評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,307評(píng)論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,447評(píng)論 0 289
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,992評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,807評(píng)論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,001評(píng)論 1 370
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,550評(píng)論 5 361
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,243評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,667評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,930評(píng)論 1 287
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,709評(píng)論 3 393
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,996評(píng)論 2 374

推薦閱讀更多精彩內(nèi)容