4
votes

I'm using GAE, Google App Engine with Webapp using Python.

I've been trying to implement a custom error handler, or template, or along those lines. GAE provides some documentation here however it doesn't provide enough in the example for implementation (for me).

I've also looked at all these wonderful examples on another StackOverflow question here - but cannot understand how to implement it into my current main.py file.

import os
from google.appengine.ext import webapp
from google.appengine.ext.webapp import util
from google.appengine.ext.webapp import template

class MainHandler(webapp.RequestHandler):
 def get (self, q):
    if q is None:
      q = 'static/index.html'

    path = os.path.join (os.path.dirname (__file__), q)
    self.response.headers ['Content-Type'] = 'text/html'
    self.response.out.write (template.render (path, {}))

def main ():
  application = webapp.WSGIApplication ([('/(.*html)?', MainHandler)], debug=False)
  util.run_wsgi_app (application)

if __name__ == '__main__':
  main ()

I've tried making another class, and implementing it before the MainHandler as well as a new def in the MainHandler. The only times I've gotten the 404 to display, it's displayed globally, meaning even the index.html file was a "404".

The last thing I tried was implementing something along the lines of:

if not os.path.exists (_file_):
 self.redirect(/static/error/404.html)

My app.yaml file is:

application: appname
version: 1
runtime: python
api_version: 1

error_handlers:
  - file: static/error/404.html

  - error_code: over_quota
    file: static/error/404.html

handlers:
- url: /(.*\.(gif|png|jpg|ico|js|css))
  static_files: \1
  upload: (.*\.(gif|png|jpg|ico|js|css))

- url: /robots.txt
  static_files: robots.txt
  upload: robots.txt 

- url: /favicon.ico
  static_files: favicon.ico
  upload: favicon.ico    

- url: .*
  script: main.py

I cannot find any guides/tutorials to the implementation of the 404 handler, just code extracts.

Much appreciated everyone!

Edit: As per clarification from Hans below, I want to return a 404 when a file (or directory) is not present in the filesystem.

I've tried:

class ErrorHandler(webapp.RequestHandler):
  def get(self):
     if not os.path.isfile(_file_):
        self.redirect('/static/error/404.html')

to no avail. What's the correct implementation/syntax?

Edit: To Voscausa

import os
from google.appengine.ext import webapp
from google.appengine.ext.webapp import util
from google.appengine.ext.webapp import template
import logging

import webapp2

def handle_404(request, response, exception):
    logging.exception(exception)
    response.write('Oops! I could swear this page was here!')
    response.set_status(404)

def handle_500(request, response, exception):
    logging.exception(exception)
    response.write('A server error occurred!')
    response.set_status(500)

app = webapp2.WSGIApplication([
    webapp2.Route('/', handler='handlers.HomeHandler', name='home')
])
app.error_handlers[404] = handle_404
app.error_handlers[500] = handle_500

class MainHandler(webapp.RequestHandler):
  def get (self, q):
    if q is None:
      q = 'static/index.html'

    path = os.path.join (os.path.dirname (__file__), q)
    self.response.headers ['Content-Type'] = 'text/html'
    self.response.out.write (template.render (path, {}))

def main ():
  application = webapp.WSGIApplication ([('/(.*html)?', MainHandler)], debug=True)
  util.run_wsgi_app (application)

if __name__ == '__main__':
  main ()
2

2 Answers

0
votes

Have a look at: http://webapp-improved.appspot.com/guide/exceptions.html for handling 404 and 500 exceptions. Webapp2 is now the preferred framework for GAE python applications.

0
votes

SOLUTION 1: Have appengine take care of your static files

You can have GAE handle your static files for you, like this:

application: appname
version: 1
runtime: python
api_version: 1

handlers:
- url: /static
  static_dir: static

- url: .*
  script: main.py

This is better as serving static files is much easier when it is done for you, and it will also not count as much towards your CPU quota.

There is just one warning. You cannot specify a custom error handled in case a file is not found below /static. As soon as a handler picks up on a url, it will try to finish the request. If the static dir handler cannot find the url, it will not hand control back to main.py, which is now your wildcard solution. It will simply return the default 404 error page from appengine.

SOLUTION 2: Serve static files from your application

If you really must create a custom 404 page for your static you have to do it in your application. (I do not advice you to do so, in case that's not clear.) In that case you were on the right track. You should create an extra handler like in your example. Just rewrite one line:

path = os.path.join(os.path.dirname(__file__), 'static', q)

In you application line, add your handler like this:

('/static/(.*)?', MainHandler),

If the file is not found, you should call self.response.set_status(404) and write whatever custom response message you need.