2012-08-25 108 views
1

我在Google App Engine上有一個靜態網站,可以下載幾個.rar文件。使用Google App Engine下載鏈接

handlers: 
- url: /(.*\.(bz2|gz|rar|tar|tgz|zip)) 
    static_files: static/\1 
    upload: static/(.*\.(bz2|gz|rar|tar|tgz|zip)) 

現在我想要做的是提供諸如/download?MyFile.rar這樣我就可以計數下載下載鏈接: 現在它是一個靜態文件處理程序定義(app.yaml中)處理看看誰在盜鏈

只要網站使用此網址(真實路徑將隱藏/不可用),我不想防止盜鏈。這樣我可以計算下載量,即使它來自外部(Google Analytics或Clicky沒有明顯處理,並且日誌記錄保留時間僅爲90天,因此不便於此目的)。

現在的問題是:如何製作一個可以爲用戶啓動文件下載的python處理程序?就像我們在很多php/asp網站上看到的一樣。

搜索了很多,讀那些2線(How do I let Google App Engine have a download link that downloads something from a database?google app engine download a file containing files)之後,似乎我能有這樣的:

self.response.headers['Content-Type'] = 'application/octet-stream' 
self.response.out.write(filecontent) # how do I get that content? 
#or 
self.response.headers["Content-Type"] = "application/zip" 
self.response.headers['Content-Disposition'] = "attachment; filename=MyFile.rar" # does that work? how do I get the actual path? 

我看過一個處理程序只能爲有限的時間內運行,因此它可能不爲大文件工作?

任何指導將不勝感激!

謝謝。

Romz

編輯: 得到它的工作,它讓我對所有.rar文件的單個處理器。它可以讓我的url看起來像直接鏈接(example.com/File.rar),但實際上是在python中處理的(所以我可以檢查引用者,計算下載等)。

這些文件實際上位於不同的子文件夾中,並且由於生成路徑的方式而不受真正的直接下載的保護。我不知道是否有其他字符(比'/'和'\')應該被過濾出來,但這種方式沒有人應該能夠訪問父文件夾中的任何其他文件或任何其他文件。

雖然我不知道這些對我的配額和文件大小的限制意味着什麼。

的app.yaml

handlers: 
- url: /(.*\.rar) 
    script: main.app 

main.py

from google.appengine.ext import webapp 
from google.appengine.api import memcache 
from google.appengine.ext import db 
import os, urlparse 

class GeneralCounterShard(db.Model): 
    name = db.StringProperty(required=True) 
    count = db.IntegerProperty(required=True, default=0) 

def CounterIncrement(name): 
    def txn(): 
     counter = GeneralCounterShard.get_by_key_name(name) 
     if counter is None: 
      counter = GeneralCounterShard(key_name=name, name=name) 
     counter.count += 1 
     counter.put() 
    db.run_in_transaction(txn) 
    memcache.incr(name) # does nothing if the key does not exist 

class MainPage(webapp.RequestHandler): 
    def get(self): 

    referer = self.request.headers.get("Referer") 
    if (referer and not referer.startswith("http://www.example.com/")): 
     self.redirect('http://www.example.com') 
     return 

    path = urlparse.urlparse(self.request.url).path.replace('/', '').replace('\\', '') 
    fullpath = os.path.join(os.path.dirname(__file__), 'files/'+path) 
    if os.path.exists(fullpath): 
     CounterIncrement(path) 
     self.response.headers['Content-Type'] = 'application/zip' 
     self.response.headers["Content-Disposition"] = 'attachment; filename=' + path 
     self.response.out.write(file(fullpath, 'rb').read()) 
    else: 
     self.response.out.write('<br>The file does not exist<br>') 


app = webapp.WSGIApplication([('/.*', MainPage)], debug=False) 
+1

只要您的文件很小,這將工作正常。如果它們較大,則應將它們存儲在Blobstore中,並使用直接Blobstore支持服務它們,這樣就不必將它們讀入應用程序的內存中。 –

回答

0

您可以嘗試使用self.resquest.referer

繼承人如何做到這一點。有一個「點擊這裏」下載鏈接到您的文件下載頁面,那麼你可以有一個FileDownloadHandler,其中name/id /或whaterver作爲參數傳遞,在這個處理程序中,檢查引用是否是'下載頁面'所以你知道這個請求是否是有效的下載。如果是,則提供該文件,如果沒有,則重定向或執行一些錯誤。

只是一個想法

0

你可以存儲文件內容在Blob存儲,並從那裏發球局,但在巨大的文件和緩慢的客戶端的情況下,你會達到時間限制(~30秒)

另一種選擇是有一個簡單的手柄r統計下載,然後發出臨時重定向(HTTP 302)到真正的下載鏈接。它可以讓你提供大文件,但它仍然可以熱鏈接真正的文件,而不是處理程序的URL。

+2

請求時間限制是60秒,而不是30秒,它們不適用於上傳或下載時間 - 所以使用blobstore無論大小如何都可以正常工作。 –