下载Google App Engine的链接

时间:2012-08-25 22:48:57

标签: python google-app-engine download

我在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网站上看到的一样。

经过大量搜索并阅读了这两个主题(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文件。它让我的网址看起来像直接链接(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)

2 个答案:

答案 0 :(得分:0)

您可以将文件内容存储在Blob存储中并从那里进行服务,但是如果文件很大且客户端速度很慢,您将达到时间限制(~30秒)

另一个选择是拥有一个简单的处理程序来计算下载,然后发出临时重定向(HTTP 302)到真正的下载链接。它将允许您提供大型文件,但仍然可以热链接真实文件而不是处理程序URL。

答案 1 :(得分:0)

您可以尝试使用self.resquest.referer

你是怎么做到的。点击“点击此处”下载指向您的文件下载页面的链接,然后您可以FileDownloadHandler,其中name / id /或whaterver作为参数传递,处理程序,检查引用程序是否为“下载页面”,以便您知道该请求是否为有效下载。如果是,则提供文件,如果没有,则重定向或执行一些错误。

只是一个想法