Tải lên tệp trong Google App Engine


79

Tôi đang lên kế hoạch tạo một ứng dụng web cho phép người dùng hạ cấp các tệp dự án studio trực quan của họ. Tuy nhiên, có vẻ như Google App Engine chấp nhận tải lên tệp và lưu trữ tệp phẳng trên Máy chủ Google thông qua db.TextPropertydb.BlobProperty.

Tôi rất vui khi bất cứ ai có thể cung cấp mẫu mã (cả phía máy khách và phía máy chủ) về cách có thể thực hiện điều này.


@ user858915 Liên kết bị hỏng :(
Marco

Câu trả lời:


44

Đây là một tệp hoàn chỉnh, đang hoạt động. Tôi đã lấy bản gốc từ trang Google và sửa đổi để làm cho nó giống với thế giới thực hơn một chút.

Một số điều cần lưu ý:

  1. Mã này sử dụng API BlobStore
  2. Mục đích của dòng này trong lớp ServeHandler là "sửa chữa" khóa để nó loại bỏ bất kỳ lỗi sai tên nào có thể xảy ra trong trình duyệt (tôi không quan sát thấy khóa nào trong Chrome)

    blob_key = str(urllib.unquote(blob_key))
    
  3. Mệnh đề "save_as" ở cuối điều này rất quan trọng. Nó sẽ đảm bảo rằng tên tệp không bị sai khi nó được gửi đến trình duyệt của bạn. Hãy thoát khỏi nó để quan sát những gì xảy ra.

    self.send_blob(blobstore.BlobInfo.get(blob_key), save_as=True)
    

Chúc may mắn!

import os
import urllib

from google.appengine.ext import blobstore
from google.appengine.ext import webapp
from google.appengine.ext.webapp import blobstore_handlers
from google.appengine.ext.webapp import template
from google.appengine.ext.webapp.util import run_wsgi_app

class MainHandler(webapp.RequestHandler):
    def get(self):
        upload_url = blobstore.create_upload_url('/upload')
        self.response.out.write('<html><body>')
        self.response.out.write('<form action="%s" method="POST" enctype="multipart/form-data">' % upload_url)
        self.response.out.write("""Upload File: <input type="file" name="file"><br> <input type="submit" name="submit" value="Submit"> </form></body></html>""")

        for b in blobstore.BlobInfo.all():
            self.response.out.write('<li><a href="https://stackoverflow.com/serve/%s' % str(b.key()) + '">' + str(b.filename) + '</a>')

class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
    def post(self):
        upload_files = self.get_uploads('file')
        blob_info = upload_files[0]
        self.redirect('/')

class ServeHandler(blobstore_handlers.BlobstoreDownloadHandler):
    def get(self, blob_key):
        blob_key = str(urllib.unquote(blob_key))
        if not blobstore.get(blob_key):
            self.error(404)
        else:
            self.send_blob(blobstore.BlobInfo.get(blob_key), save_as=True)

def main():
    application = webapp.WSGIApplication(
          [('/', MainHandler),
           ('/upload', UploadHandler),
           ('/serve/([^/]+)?', ServeHandler),
          ], debug=True)
    run_wsgi_app(application)

if __name__ == '__main__':
  main()

Tuyệt vời mà công trình này cho tất cả mọi người ngoại trừ đối với tôi ... self.__uploadstrong blobstore_handlerNonekhi tôi cố gắng này.
Tim

49

Trên thực tế, câu hỏi này được trả lời trong tài liệu App Egnine. Xem ví dụ về Tải lên Hình ảnh Người dùng .

Mã HTML, bên trong <form> </form>:

<input type = "file" name = "img" />

Mã Python:

Sổ lưu bút lớp (webapp.RequestHandler):
  bài def (bản thân):
    lời chào = Greeting ()
    if users.get_current_user ():
      Welcome.author = users.get_current_user ()
    welcome.content = self.request.get ("nội dung")
    avatar = self.request.get ("img")
    Welcome.avatar = db.Blob (ảnh đại diện)
    welcome.put ()
    self.redirect ('/')

Không thích cách tiếp cận này khiến bạn mất thông tin loại kịch câm.
santiagobasulto,

@santiagobasulto: Tại sao bạn không tự mình kiểm tra nó?
vietean

Tôi không muốn kiểm tra nó. Khi bạn phải hiển thị một hình ảnh, bạn phải cung cấp thông tin loại kịch câm (cho dù hình ảnh là JPG, GIF, v.v.) vì vậy, bạn phải cung cấp tiêu đề HTTP loại nội dung. Nếu bạn tải lên hình ảnh với giải pháp bạn cung cấp thì trong tương lai bạn sẽ không biết loại nội dung của pic, ergo, bạn không thể đặt tiêu đề, ergo, các trình duyệt cũ sẽ có vấn đề để hiển thị hình ảnh ( becouse sự vắng mặt của các kiểu nội dung)
santiagobasulto

1
Nếu bạn không kiểm tra loại kịch câm mà bạn đang tin tưởng ứng dụng khách, bạn sẽ dễ bị tấn công bởi mũ đen hoặc các loại kịch câm được định cấu hình sai trong ứng dụng khách. Nếu bạn sắp làm điều đó, bạn chỉ có thể tin tưởng vào chính phần mở rộng tệp.
Nacho Coloma

10

Có một chủ đề trong Google Groups về nó:

Tải lên tệp

Với rất nhiều mã hữu ích, cuộc thảo luận đó đã giúp tôi rất nhiều trong việc tải tệp lên.


6

Google đã phát hành một dịch vụ để lưu trữ các tệp lớn. Hãy xem tài liệu API của blobstore . Nếu tệp của bạn> 1MB, bạn nên sử dụng nó.


Cách lưu tệp> 1mb. Tôi đang sử dụng github.com/ckopanos/django-google-cloud-storage
Geo-cốp

6

Tôi thử nó hôm nay, Nó hoạt động như sau:

phiên bản sdk của tôi là 1.3.x

trang html:

<form enctype="multipart/form-data" action="/upload" method="post" > 
<input type="file" name="myfile" /> 
<input type="submit" /> 
</form> 

Mã máy chủ:

file_contents = self.request.POST.get('myfile').file.read() 

3

Nếu bạn vẫn gặp sự cố, hãy kiểm tra xem bạn có đang sử dụng enctype trong thẻ biểu mẫu không

Không:

<form encoding="multipart/form-data" action="/upload">

Đúng:

<form enctype="multipart/form-data" action="/upload">

Tôi đã nhận được một lỗi mã hóa trước khi tôi thực hiện câu trả lời của bạn
Jader Dias

1
Một vấn đề thực sự khó chịu đối với tôi khi tôi làm điều này là không bao gồm "kích thước" cho loại đầu vào tệp. Tôi đã thử nghiệm với Safari dường như có độ dài tệp rất ngắn theo mặc định (?) Và tất cả những gì tôi nhận được trong GAE cho nội dung của tệp là tên của tệp. Chỉ một lời cảnh báo có thể giúp ai đó bớt đau đầu.
John Carter

1

Bạn không thể lưu trữ tệp vì không có hệ thống tệp truyền thống. Bạn chỉ có thể lưu trữ chúng trong DataStore của riêng họ (trong trường được xác định là BlobProperty )

Có một ví dụ trong liên kết trước:

class MyModel(db.Model):
  blob = db.BlobProperty()

obj = MyModel()
obj.blob = db.Blob( file_contents )

1

Cá nhân tôi thấy hướng dẫn được mô tả ở đây hữu ích khi sử dụng thời gian chạy Java với GAE. Vì một số lý do, khi tôi cố gắng tải tệp lên bằng

<form action="/testservelet" method="get" enctype="multipart/form-data">
    <div>
        Myfile:<input type="file" name="file" size="50"/>
    </div>

    <div>
        <input type="submit" value="Upload file">
    </div>
</form>

Tôi thấy rằng lớp HttpServlet của mình vì một số lý do sẽ không chấp nhận biểu mẫu có thuộc tính 'enctype'. Tuy nhiên, xóa nó hoạt động, điều này có nghĩa là tôi không thể tải lên bất kỳ tệp nào.


1
Có thể do bạn đang sử dụng phương thức get, thay vào đó hãy thử đặt nó để đăng. Tôi không chắc liệu nó có hoạt động hay không nhưng rất đáng để thử.
slutnick

0

Không có tệp phẳng nào được lưu trữ trong Google App Engine. Mọi thứ phải đi vào Kho dữ liệu hơi giống với cơ sở dữ liệu quan hệ nhưng không hoàn toàn.

Bạn có thể lưu trữ các tập tin như TextProperty hoặc BlobProperty thuộc tính.

Giới hạn 1MB đối với các mục nhập DataStore có thể là một vấn đề.


Cách lưu tệp lớn hơn 1mb. Tôi đang sử dụng github.com/ckopanos/django-google-cloud-storage
Geo Jacob

0

Tôi đã quan sát thấy một số hành vi lạ khi tải tệp lên App Engine. Khi bạn gửi biểu mẫu sau:

<form method="post" action="/upload" enctype="multipart/form-data">
    <input type="file" name="img" />
    ...
</form>

Và sau đó bạn trích xuất imgtừ yêu cầu như sau:

img_contents = self.request.get('img')

Các img_contentsbiến là một str()trong Google Chrome, nhưng đó là unicode trong Firefox. Và như bạn bây giờ, hàm db.Blob()tạo nhận một chuỗi và sẽ gây ra lỗi nếu bạn truyền vào một chuỗi unicode.

Có ai biết làm thế nào điều này có thể được sửa chữa?

Ngoài ra, điều tôi thấy hoàn toàn lạ là khi tôi sao chép và dán ứng dụng Guestbook (có ảnh đại diện), nó hoạt động hoàn hảo. Tôi làm mọi thứ theo cùng một cách trong mã của mình, nhưng nó sẽ không hoạt động. Tôi rất gần với việc nhổ tóc của mình.


2
: D Form nói: mutlipart / form-data thay vì multiart / form-data. Chrome đủ thông minh để sửa lỗi chính tả, Firefox thì không.
Honza Pokorny

0

Có một cách sử dụng hệ thống tệp phẳng (Ít nhất trong quan điểm sử dụng)

dự án Hệ thống tệp ảo Google App Engine này . được triển khai với sự trợ giúp của các API kho dữ liệu và memcache để mô phỏng một hệ thống tệp thông thường. Sử dụng thư viện này, bạn có thể sử dụng trong dự án truy cập hệ thống tệp tương tự (đọc và ghi) .

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.