2013-07-07 55 views
19

我有應用程序,用戶的照片是私人的。我在AWS s3中存儲照片(縮略圖)。用戶可以在網站上看到他的照片(即縮略圖)。現在我的問題是如何提供這些文件。我已評估的一些選項爲:在express/nodejs應用程序中存儲在S3中的文件

  • 使用簽署的url生成從CloudFront(或AWS)提供文件。但問題是每次用戶刷新頁面時,我都必須重新創建這麼多已簽名的URL並加載它。因此,我不能在瀏覽器中緩存圖像,這將是一個不錯的選擇。無論如何,仍然在JavaScript中做?由於安全問題,我無法長時間保持這些網址的有效性。其次,在這段時間內,如果有人獲得了該網址,他可以查看該文件,而無需通過應用程序的身份驗證。
  • 其他選項是在從S3服務器進行流式傳輸之後,從我的快速應用程序本身提供文件。這使我可以擁有http緩存頭,因此可以啓用瀏覽器緩存。它還確保沒有人可以查看文件,而無需進行身份驗證。理想情況下,我想流式傳輸文件,並使用NGINX代理中繼將另一端流式傳輸到NGINX。但是,正如我所看到的,只有當文件存在於同一個系統文件中時纔有可能。但是在這裏,我必須流式傳輸並在流完成時返回。不想在本地存儲文件。

我不能評估哪兩個選項是更好的選擇?我想盡可能多地將工作重定向到S3或cloudfront,但即使使用單個url也會將請求首先發送到我的服務器。我也想要緩存功能。

那麼最理想的方法是什麼?與這些方法有關的特定問題的答案?

回答

19

我只是從S3流。這很容易,並且簽名的URL更加困難。只需確保在將圖像上傳到S3時設置了content-typecontent-length標題。

var aws = require('knox').createClient({ 
    key: '', 
    secret: '', 
    bucket: '' 
}) 

app.get('/image/:id', function (req, res, next) { 
    if (!req.user.is.authenticated) { 
    var err = new Error() 
    err.status = 403 
    next(err) 
    return 
    } 

    aws.get('/image/' + req.params.id) 
    .on('error', next) 
    .on('response', function (resp) { 
    if (resp.statusCode !== 200) { 
     var err = new Error() 
     err.status = 404 
     next(err) 
     return 
    } 

    res.setHeader('Content-Length', resp.headers['content-length']) 
    res.setHeader('Content-Type', resp.headers['content-type']) 

    // cache-control? 
    // etag? 
    // last-modified? 
    // expires? 

    if (req.fresh) { 
     res.statusCode = 304 
     res.end() 
     return 
    } 

    if (req.method === 'HEAD') { 
     res.statusCode = 200 
     res.end() 
     return 
    } 

    resp.pipe(res) 
    }) 
}) 
+1

我會以你的答案爲例。非常感謝。但是,如果你不介意你是否可以再幫助我一件事。使用AWS-SDK更好還是knox? –

+1

從未嘗試過aws-sdk。然而,Knox維護者更多地參與節點社區。 –

+1

但是??然而你沒有提到什麼? –

1

如果照片真的需要保持私密,我會關注使用CloudFront選項。看起來你在管理自己的安全策略方面會有更多的靈活性。我認爲nginx設置可能比必要的更復雜。 Express應該可以提供非常好的性能,可以作爲遠程代理使用,它使用請求從S3獲取項目並將其傳送給授權用戶。我強烈推薦看看Asset Rack,它使用散列簽名來啓用瀏覽器中的永久緩存。您將無法使用默認的機架,因爲您需要計算每個文件的MD5(可能是上載?),這是流式傳輸時無法完成的。但取決於您的應用程序,它可以爲瀏覽器從不需要重新獲取圖像節省大量的工作量。

+0

如果我不流的照片,而等待文件被下載到緩衝區,比給它返回給用戶? https://github.com/techpines/asset-rack/blob/master/lib/asset.coffee#L200: –

+1

當您收到文件,使用相同的MD5哈希是資產機架採用指紋識別它。使用knox將文件名上傳到S3。然後,當用戶請求文件時,請使用everyauth或passport進行身份驗證,如果成功,請使用knox從S3獲取文件並將其提供給用戶,並將緩存控制設置爲1年緩存,資產架的使用方式。 – dankohn

+0

是啊...您的想法看起來不錯,但爲什麼我應該knox,而我可以使用AWS-SDK。 –

0

關於第二個選項,您應該可以設置cache control headers directly in S3

關於你的第一個選項。你有沒有考慮以不同的方式保護你的圖像? 當您在S3中存儲圖像時,是否可以使用散列且隨機的文件名?如果文件名難以猜出,這將是非常直接的方式+這種方式你不會有任何性能問題,查看圖像回來。

這是Facebook使用的技巧。只要知道URL,您仍然可以在退出時查看圖像。

+0

我不希望任何具有該網址的人都能夠查看圖片。在S3中直接設置緩存控制標題的另一個問題是,每次用戶想要查看時,他都會嚮應用程序請求,並生成一個url併發送給他,所以基本上緩存控制無關緊要。 –

+0

明白了,我已經發布了另一個選項 –

+0

你在哪裏發佈了另一個選項?如果你的意思是Facebook技術比我已經讓你知道我沒有任何人的網址能夠查看圖像,如果他沒有權利。 –

7

如果你重定向用戶使用瀏覽器302 Found將根據其cache-control頭緩存所產生的圖像標識的URL,並不會要求它的第二次。

爲了防止瀏覽器緩存中標識的URL本身,你應該與它一起發送正確Cache-Control頭:

Cache-Control: private, no-cache, no-store, must-revalidate 

因此,下一次它會發送請求到原始地址和將被重定向到一個新的簽署的網址。

您可以使用signedUrl method生成帶knox的簽名url。

但不要忘記爲每個上傳的圖像設置正確的標題。我建議您同時使用Cache-ControlExpires標頭,因爲某些瀏覽器不支持Cache-Control標頭,並且Expires只允許您設置絕對過期時間。

第二個選項(通過您的應用程序流式傳輸圖像)可以更好地控制情況。例如,您可以根據當前的日期和時間爲每個響應生成Expires標題。

但速度怎麼樣?使用簽名的url有兩個好處,可能會影響頁面加載速度。

首先,你不會超載你的服務器。如果速度很快,則生成已簽名的網址,因爲您只是對您的AWS憑據進行哈希處理並且通過您的服務器流式傳輸圖像,您需要在頁面加載期間保持大量額外的連接。無論如何,除非你的服務器很難加載,否則它不會有任何實際的區別。

其次,瀏覽器在頁面加載期間每個主機名只保留兩個並行連接。因此,瀏覽器將在下載圖像時並行解析圖像。它還會阻止下載圖像,阻止下載任何其他資源。

無論如何,要絕對確定你應該運行一些基準測試。我的回答是基於我對HTTP規範的知識以及我在網絡開發方面的經驗,但我從來沒有試圖以我自己的方式提供圖像。直接從S3提供長緩存生存期的公共圖像可以提高頁面速度,如果您通過重定向完成,我相信情況不會改變。

您應該記住,通過您的服務器流式傳輸圖像將帶來Amazon CloudFront的所有優勢。但只要你直接從S3提供內容,這兩個選項都可以正常工作。

因此,有兩種情況使用已簽署的網址應該加速你的頁面時:

  • 如果你有一個單一頁面上大量的圖片。
  • 如果您使用CloudFront提供圖像。

如果你只有在每一頁上幾張圖片,並直接從S3爲他們提供服務,你可能不會看到任何差別。

重要更新

我進行了一些測試,發現我錯了有關緩存。瀏覽器確實緩存了他們被重定向到的圖片。但它將緩存的圖像與它重定向到的網址相關聯,而不是與原始網址相關聯。因此,當瀏覽器第二次加載頁面時,它會再次從服務器請求圖像,而不是從緩存中獲取圖像。當然,如果服務器使用相同的重定向url進行響應,它會首次響應,瀏覽器將使用它的緩存,但對於已簽名的url,情況並非如此。

我發現,迫使瀏覽器緩存標識的URL以及接收到的數據解決了這個問題。但我不喜歡緩存無效重定向網址的想法。我的意思是,如果瀏覽器以某種方式錯過了圖像,它會嘗試使用緩存中的無效簽名url再次請求它。所以,我認爲這不是一個選擇。

如果CloudFront的服務更快的圖像,或者如果瀏覽器限制每個主機並行下載的數量,使用瀏覽器緩存的優勢,通過你的服務器超出管道圖像的所有缺點都無所謂。

它看起來像大多數社交網絡通過隱藏其真實URL背後的一些私人代理解決了私人圖像的問題。因此,他們將所有內容存儲在公共服務器上,但沒有辦法在未經授權的情況下將url鏈接到私人圖像。當然,如果您將在新標籤中打開私密圖片並將網址發送給您的朋友,他也可以看到圖片。所以,如果它不適合你,那麼最好使用Jonathan Ong's solution

+0

你確定它會比生成signedUrl並重定向它慢嗎?關於你能指定哪些東西,速度較慢? –

+0

@SaranshMohapatra我更新了我的答案。 –

+0

好的,謝謝你的回答。我會以結果爲基準並回復你。這樣可以對其他人有用。而你的答案是我發現的最具描述性的,所以再次感謝。 –

相關問題