2012-08-25 52 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无论大小如何都可以正常工作。 –