【发布时间】:2012-08-25 22:48:57
【问题描述】:
我在 Google App Engine 上有一个静态网站,可以下载一些 .rar 文件。 现在它由静态文件处理程序定义(app.yaml)处理:
handlers:
- url: /(.*\.(bz2|gz|rar|tar|tgz|zip))
static_files: static/\1
upload: static/(.*\.(bz2|gz|rar|tar|tgz|zip))
现在我想做的是提供一个像 /download?MyFile.rar 这样的下载链接,这样我就可以计算下载次数并查看谁在盗链。
只要网站使用此网址,我就不想阻止盗链(真实路径将被隐藏/不可用)。这样我就可以计算下载量,即使它来自外部(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?
我确实读到处理程序只能运行有限的时间,所以它可能不适用于大文件?
任何指导将不胜感激!
谢谢。
罗兹
编辑: 让它工作,它让我有一个处理所有 .rar 文件的处理程序。它让我拥有看起来像直接链接(example.com/File.rar)但实际上是在 python 中处理的 URL(因此我可以检查引用者、计算下载量等)。
这些文件实际上位于不同的子文件夹中,并且由于路径的生成方式,可以防止真正的直接下载。我不知道是否还有其他字符(除了“/”和“\”)应该被过滤掉,但是这样就没有人应该能够访问父文件夹中的任何其他文件或其他任何文件。
虽然我真的不知道这对我的配额和文件大小限制意味着什么。
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)
【问题讨论】:
-
只要您的文件很小,它就可以正常工作。如果它们更大,您应该将它们存储在 blobstore 中并使用直接 blobstore 支持来提供它们,因此您不必将它们读入应用程序的内存中。
标签: python google-app-engine download