Google App Engine에서 파일 업로드


79

사용자가 Visual Studio 프로젝트 파일을 다운 그레이드 할 수있는 웹 앱을 만들 계획입니다. 그러나, 구글 앱 엔진은 파일 업로드 및 통해 구글 서버에 저장하는 플랫 파일 받아들이는 것 db.TextProperty등을 db.BlobProperty.

이 작업을 수행 할 수있는 방법에 대한 코드 샘플 (클라이언트 및 서버 측 모두)을 누구든지 제공 할 수있어 기쁩니다.


@ user858915 링크가 끊어졌습니다 :(
Marco

답변:


44

여기에 완전한 작업 파일이 있습니다. Google 사이트에서 원본을 가져 와서 좀 더 현실적으로 만들도록 수정했습니다.

주의해야 할 몇 가지 사항 :

  1. 이 코드는 BlobStore API를 사용합니다.
  2. ServeHandler 클래스에서이 줄의 목적은 키를 "고정"하여 브라우저에서 발생할 수있는 모든 이름 변경을 제거하는 것입니다 (Chrome에서는 관찰되지 않음).

    blob_key = str(urllib.unquote(blob_key))
    
  3. 이 끝에있는 "save_as"절이 중요합니다. 파일 이름이 브라우저로 전송 될 때 왜곡되지 않도록합니다. 무슨 일이 일어나는지 관찰하기 위해 그것을 제거하십시오.

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

행운을 빕니다!

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()

놀라운 나를 제외한 모든 사람들에게이 작품은 ... 것이 self.__uploads있는 blobstore_handler것입니다 None내가 이것을 할 때.
Tim

49

실제로이 질문은 App Egnine 문서에 답변되어 있습니다. 사용자 이미지 업로드에 대한 예를 참조하십시오 .

<form> </ form> 내부의 HTML 코드 :

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

Python 코드 :

class Guestbook (webapp.RequestHandler) :
  def post (self) :
    greeting = 인사말 ()
    users.get_current_user () :
      greeting.author = users.get_current_user ()
    greeting.content = self.request.get ( "content")
    avatar = self.request.get ( "img")
    greeting.avatar = db.Blob (아바타)
    greeting.put ()
    self.redirect ( '/')

이 접근 방식이 마음에 들지 않으면 MIME 유형 정보가 손실됩니다.
santiagobasulto

@santiagobasulto : 왜 우리 스스로 확인하지 않습니까?
vietean

확인하고 싶지 않습니다. 이미지를 표시해야하는 경우 MIME 유형 정보 (이미지가 JPG, GIF 등)를 제공해야하므로 콘텐츠 유형 HTTP 헤더를 제공해야합니다. 제공하는 솔루션으로 이미지를 업로드하면 앞으로 사진의 콘텐츠 유형을 알 수 없습니다. ergo, 헤더를 설정할 수 없습니다. ergo, 오래된 브라우저는 이미지를 표시하는 데 문제가 있습니다 )이 콘텐츠 형식의 부재의 렸기 때문에
santiagobasulto

1
클라이언트를 신뢰하는 MIME 유형을 확인하지 않으면 클라이언트에서 블랙 햇 공격이나 잘못 구성된 MIME 유형에 노출됩니다. 그렇게하려는 경우 파일 확장자 자체를 신뢰할 수 있습니다.
Nacho Coloma

10

Google 그룹스에 이에 대한 스레드가 있습니다.

파일 업로드

유용한 코드가 많기 때문에이 토론은 파일 업로드에 많은 도움이되었습니다.


6

Google은 대용량 파일 저장 서비스를 출시했습니다. blobstore API 문서를 살펴보세요 . 파일이 1MB를 초과하는 경우이를 사용해야합니다.


파일 저장 방법> 1mb. 저는 github.com/ckopanos/django-google-cloud-storage를 사용하고 있습니다
Geo Jacob

6

나는 오늘 그것을 시도한다, 그것은 다음과 같이 작동한다 :

내 SDK 버전은 1.3.x입니다.

html 페이지 :

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

서버 코드 :

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

3

여전히 문제가있는 경우 양식 태그에서 enctype을 사용하고 있는지 확인하십시오.

아니:

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

예:

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

나는 당신의 대답 구현하기 전에 나는 인코딩 오류가 발생했습니다
데르 디아스을

1
이 작업을 할 때 정말 짜증나는 걸림돌은 파일 입력 유형에 "크기"를 포함하지 않는 것이 었습니다. 기본적으로 파일 길이가 매우 짧은 (?) Safari로 테스트하고 있었는데 파일 내용에 대해 GAE에서 얻은 것은 파일 이름뿐이었습니다. 경미한 두통을 덜어 줄 수있는 경고의 한마디.
John Carter

1

기존 파일 시스템이 없기 때문에 파일을 저장할 수 없습니다. 당신은 (A로 정의 된 필드에 자신의 데이터 저장소에 저장할 수 있습니다 BlobProperty )

이전 링크에 예가 있습니다.

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

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

1

개인적으로 여기에 설명 된 튜토리얼 이 GAE와 함께 Java 런타임을 사용할 때 유용하다는 것을 알았습니다 . 어떤 이유로 파일을 업로드하려고 할 때

<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>

어떤 이유로 든 내 HttpServlet 클래스가 'enctype'속성이있는 양식을 허용하지 않는다는 것을 발견했습니다. 그러나 제거하면 파일을 업로드 할 수 없습니다.


1
get 메서드를 사용하고 있기 때문일 수 있습니다. 대신 게시하도록 설정해보세요. 그것이 효과가 있는지 확실하지 않지만 시도해 볼 가치가 있습니다.
slashnick

0

Google App Engine에는 플랫 파일이 없습니다. 모든 것이 Datastore 로 이동해야합니다. 관계형 데이터베이스와 비슷하지만 그렇지 않은 .

파일을 TextProperty 또는 BlobProperty 속성 으로 저장할 수 있습니다 .

문제가 될 수도 있고 아닐 수도있는 데이터 저장소 항목에는 1MB 제한이 있습니다.


1MB보다 큰 파일을 저장하는 방법. 저는 github.com/ckopanos/django-google-cloud-storage를
Geo Jacob

0

App Engine에 파일을 업로드 할 때 이상한 동작이 관찰되었습니다. 다음 양식을 제출할 때 :

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

그런 다음 다음 img과 같이 요청에서 추출합니다 .

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

img_contents변수는있다 str()구글 크롬에 있지만, 파이어 폭스에서 유니 코드입니다. 그리고 지금과 같이 db.Blob()생성자는 문자열을 취하고 유니 코드 문자열을 전달하면 오류를 발생시킵니다.

누구든지 이것이 어떻게 고칠 수 있는지 알고 있습니까?

또한 방명록 애플리케이션 (아바타 포함)을 복사하여 붙여 넣으면 완벽하게 작동한다는 점이 정말 이상합니다. 내 코드에서 모든 것을 똑같은 방식으로 수행하지만 작동하지 않습니다. 나는 내 머리카락을 뽑는 데 매우 가깝습니다.


2
: D 형식은 다음과 같습니다 : multipart / form-data 대신 mutlipart / form-data. Chrome은 오타를 수정할만큼 똑똑하지만 Firefox는 그렇지 않습니다.
Honza Pokorny

0

플랫 파일 시스템 을 사용하는 방법이 있습니다 (사용 관점에서 이상)

Google App Engine 가상 파일 시스템 프로젝트가 있습니다. 일반 파일 시스템을 에뮬레이트하기 위해 데이터 저장소 및 Memcache API의 도움으로 구현됩니다. 이 라이브러리를 사용하면 비슷한 파일 시스템 액세스 (읽기 및 쓰기) 를 프로젝트에 사용할 수 있습니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.