问题
I want to split my App Engine implementation into several files. So I wrote in my app.yaml file:
runtime: python27
api_version: 1
threadsafe: true
handlers:
- url: /imageuploader
script: imageuploader.app
- url: /search
script: main.app
- url: /
static_files: index.html
upload: index.html
libraries:
- name: MySQLdb
version: "latest"
Basically I search and image upload to be on different paths and root path to have index file.
Here are my handlers:
main.py:
class MainPage(webapp2.RequestHandler):
def get(self):
#Implementation
app = webapp2.WSGIApplication([
('/', MainPage),
], debug=True)
imageuploader.py:
class UserPhoto(ndb.Model):
blob_key = ndb.BlobKeyProperty()
class PhotoUploadFormHandler(webapp2.RequestHandler):
def get(self):
# [START upload_url]
upload_url = blobstore.create_upload_url('/upload_photo')
# [END upload_url]
# [START upload_form]
# To upload files to the blobstore, the request method must be "POST"
# and enctype must be set to "multipart/form-data".
self.response.out.write("""
<html><body>
<form action="{0}" method="POST" enctype="multipart/form-data">
Upload File: <input type="file" name="file"><br>
<input type="submit" name="submit" value="Submit">
</form>
</body></html>""".format(upload_url))
# [END upload_form]
# [START upload_handler]
class PhotoUploadHandler(blobstore_handlers.BlobstoreUploadHandler):
def post(self):
try:
upload = self.get_uploads()[0]
user_photo = UserPhoto(
user=users.get_current_user().user_id(),
blob_key=upload.key())
user_photo.put()
self.redirect('/view_photo/%s' % upload.key())
except:
self.error(500)
# [END upload_handler]
# [START download_handler]
class ViewPhotoHandler(blobstore_handlers.BlobstoreDownloadHandler):
def get(self, photo_key):
if not blobstore.get(photo_key):
self.error(404)
else:
self.send_blob(photo_key)
# [END download_handler]
app = webapp2.WSGIApplication([
('/', PhotoUploadFormHandler),
('/upload_photo', PhotoUploadHandler),
('/view_photo/([^/]+)?', ViewPhotoHandler),
], debug=True)
# [END all]
Now, the weird thing is that if I set
-url: /.*
script: main.app
It all works. I also tried /search/.+
and /imageuploader/.+
. I must have forgotten something completely obvious but I cant figure out what is it.
回答1:
Each app.yaml
route script config (like script: imageuploader.app
) requires a python file with a matching name (imageuploader.py
in this case) which is defining an app called app
(just like the main.py
does) with app routes being, of course, a subset of (or equal to) the corresponding path from the app.yaml
file (/imageuploader
in this case).
So, problems with your implementation:
- the
main.py
app path is/
- doesn't match the corresponding/search
path inapp.yaml
- none of the 3 app path patterns in
imageuploader.py
matches the corresponding/imageuploader
path inapp.yaml
- the
/
path inapp.yaml
is actually mapped to the static resourceindex.html
, so it'll be served by GAE directly - no point adding a handler for it as that handler should never be invoked (you may want to revisit the static resources mapping).
Your attempt using /.*
mapped to main.app
could only have worked before you removed the handler code now in imageuploader.py
, but should not be working with the main.py
content from your question.
Assuming your patterns in the app.yaml
are the ones you desire, these would be the app configs you'd need (to continue with your approach):
main.py:
app = webapp2.WSGIApplication([
('/search', MainPage),
], debug=True)
imageuploader.py:
app = webapp2.WSGIApplication([
('/imageuploader', ...), # TODO: revisit mappings
], debug=True)
But I'd suggest a simpler to manage approach, using webapp2's lazy loading of the handler code.
You keep a single, generic mapping in the app.yaml
, which would match any url pattern in the main.py
file:
- url: /.*
script: main.app
You have a single app route mapping definition in main.py
, but which can lazy-load handlers from both main.py
as well as other modules/files. For example something like this:
app = webapp2.WSGIApplication([
('/upload', 'imageuploader.PhotoUploadFormHandler'),
('/upload_photo', 'imageuploader.PhotoUploadHandler'),
('/view_photo/([^/]+)?', 'imageuploader.ViewPhotoHandler'),
('/main_page', MainPage),
], debug=True)
A middle-ground approach is also possible, allowing you to completely de-couple imageuploader.py
from main.py
but with a slightly more careful url pattern choice.
You could have in app.yaml
:
- url: /photo.*
script: imageuploader.app
And in imageuploader.py
have url patterns matching that /photo.*
one:
app = webapp2.WSGIApplication([
('/photo_upload_form', PhotoUploadFormHandler),
('/photo_upload', PhotoUploadHandler),
('/photo_view/([^/]+)?', ViewPhotoHandler),
], debug=True)
来源:https://stackoverflow.com/questions/39349590/app-engine-throws-404-not-found-for-any-path-but-root