Google App Engine и ошибка 404

Я настроил статический веб-сайт в GAE, используя подсказки, найденные в других местах, но не могу понять, как вернуть ошибку 404. Мой файл app.yaml выглядит так

- url: (.*)/
  static_files: static\1/index.html
  upload: static/index.html

- url: /
  static_dir: static

со всеми статическими файлами html/jpg, хранящимися в статическом каталоге. Вышеприведенное работает для существующих файлов, но возвращает файл нулевой длины, если их нет. Ответ, вероятно, состоит в том, чтобы написать скрипт на Python для возврата ошибки 404, но как вы настроите все, чтобы обслуживать существующие статические файлы, но запускать скрипт для файлов, которых нет?

Вот лог получения несуществующего файла (nosuch.html) на сервере приложений разработки:

ERROR    2008-11-25 20:08:34,084 dev_appserver.py] Error encountered reading file "/usr/home/ctuffli/www/tufflinet/static/nosuch.html":
[Errno 2] No such file or directory: '/usr/home/ctuffli/www/tufflinet/static/nosuch.html'
INFO     2008-11-25 20:08:34,088 dev_appserver.py] "GET /nosuch.html HTTP/1.1" 404 -

person ctuffli    schedule 10.10.2008    source источник
comment
Я бы назвал этот «питон», но у меня нет доступа (пока)...   -  person AJ.    schedule 11.11.2009


Ответы (9)


Вам необходимо зарегистрировать универсальный обработчик скриптов. Добавьте это в конец вашего app.yaml:

- url: /.*
  script: main.py

В main.py вам нужно будет поместить этот код:

from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app

class NotFoundPageHandler(webapp.RequestHandler):
    def get(self):
        self.error(404)
        self.response.out.write('<Your 404 error html page>')

application = webapp.WSGIApplication([('/.*', NotFoundPageHandler)],
                                     debug=True)

def main():
    run_wsgi_app(application)

if __name__ == "__main__":
    main()

Замените <Your 404 error html page> чем-то осмысленным. Или лучше используйте шаблон, вы можете прочитать, как это сделать здесь.

Пожалуйста, дайте мне знать, если у вас возникнут проблемы с настройкой.

person Alexander Kojevnikov    schedule 10.10.2008
comment
Похоже, что последняя строка в моем оригинальном app.yaml совпадает с той, которую вы предлагаете добавить. - person ctuffli; 25.11.2008
comment
Это работает, но я предпочитаю предложение Закари использовать статический обработчик для страницы 404 (см. его ответ ниже). - person David Underhill; 29.04.2010
comment
Я пытаюсь сделать это таким образом, но если я устанавливаю ошибку 404, html не отображается, использую ли я шаблон или нет. - person Richard Nienaber; 03.07.2010
comment
не работает для случаев, когда у вас разные URL-адреса, такие как domain.com/admin/.* , domain.com/.* и т. д. - person rafek; 28.10.2010
comment
Чтобы обработать этот случай (настраиваемый 404 для каждого раздела), вы добавляете ('/admin/.*', NotFoundPageHandler') в настройку своего приложения для каждого обработчика в app.yaml. - person Robert Kluin; 28.10.2010
comment
Похоже, это не работает для предложения static_dir. Кажется, что любой отсутствующий файл в static_dir возвращает свою собственную (пустую) страницу 404 вместо того, чтобы переходить к другим обработчикам. - person mgiuca; 30.05.2011
comment
Имеют ли обработчики в списке упорядоченный приоритет? Или совпадают по специфике? т. е. если бы у вас был [('/.*', NFPH), ('/.login', LoginH)], попал ли бы когда-нибудь LoginH? - person OJFord; 09.07.2014

в движке приложений Google теперь есть настраиваемые ответы на ошибки.

так что теперь вы можете добавить раздел error_handlers в ваш app.yaml, как в этом примере:

error_handlers:

- file: default_error.html

- error_code: over_quota
    file: over_quota.html
person jonmiddleton    schedule 15.09.2010
comment
где здесь должен располагаться файл HTML? - person clifgray; 15.11.2012
comment
вы можете поместить HTML в любом месте, например. error_handlers: - файл: youappname/templates/default_error.html - person jonmiddleton; 09.01.2013
comment
Примечание: ответ, следовательно, не является ответом на вопрос - person OJFord; 14.07.2015

Значительно более простой способ сделать это, не требуя каких-либо циклов ЦП, — поместить этот обработчик в конец вашего app.yaml.

- url: /.*
    static_files: views/404.html
    upload: views/404.html

Затем это позволяет вам разместить статический файл 404.html в каталоге представлений. Нет необходимости в обработчике Python. Все, что не обрабатывается в вашем app.yaml, уже попадет в него.

person Zee Spencer    schedule 13.05.2009
comment
Нет никакого способа вернуть код ответа HTTP 404 таким образом, не так ли? - person Jeremy Logan; 05.06.2009
comment
Да, все, что вам нужно сделать, это добавить заголовок в ваш HTML-файл. - person Zee Spencer; 05.06.2009
comment
Может быть, это гениально ... но это не работает в случае, когда у вас есть надлеры / контроллеры для, например, domain.com/admin/ и разные для domain.com/, и вы хотите обрабатывать domain.com/admin/notexistent, а также домен .com/несуществующая ошибка 404 - person rafek; 28.10.2010
comment
Это не правильно. Вы не можете заставить статический контент возвращать код состояния, отличный от 200. - person Nick Johnson; 28.10.2010
comment
Это также не улавливает /views/nonexistentpage.htm, когда есть предыдущая директива - url: /views \\ static_dir: html - person bobobobo; 23.03.2011
comment
Чтобы добавить к @NickJohnson - это не ограничение, это определение: если вы обслуживаете статический контент, он был найден! - person OJFord; 14.07.2015

Вы можете создать функцию для обработки ваших ошибок для любого из кодов состояния. В вашем случае 404, определите такую ​​​​функцию:

def Handle404(request, response, exception):
     response.out.write("Your error message") 
     response.set_status(404)`

В функцию response.out.write можно передать что угодно — HTML/простой текст/шаблоны. Теперь добавьте следующее объявление после объявления app.

app.error_handlers[404] = Handle404

Это сработало для меня.

person TeknasVaruas    schedule 02.06.2012

webapp2 предоставляет словарь error_handlers, который можно использовать для обслуживания пользовательских страниц ошибок. Пример ниже:

def handle_404(request, response, exception):
    logging.warn(str(exception))
    response.set_status(404)
    h = YourAppBaseHandler(request, response)
    h.render_template('notfound')

def handle_500(request, response, exception):
    logging.error(str(exception))
    response.set_status(500)
    h = YourAppBaseHandler(request, response)
    h.render_template('servererror')

app = webapp2.WSGIApplication([
    webapp2.Route('/', MainHandler, name='home')
    ], debug=True)
app.error_handlers[404] = handle_404
app.error_handlers[500] = handle_500

Дополнительные сведения доступны на страницах документации webapp2: http://webapp-improved.appspot.com/guide/app.html#error-handlers

person Romain    schedule 03.03.2014
comment
Это было очень полезно из-за характера существующих маршрутов webapp2 (страницы и подстановочные знаки), из-за которых другие решения не работали должным образом. Спасибо. - person DMTishler; 12.05.2017

Сервер dev_appserver уже возвращает 404 ответа для всего, что не соответствует сопоставлению или соответствует сопоставлению, но не существует. Сам ответ 404 не имеет тела, но это все равно 404:

$ wget -O - http://127.0.0.1:8080/foo
--2010-10-28 10:54:51--  http://127.0.0.1:8080/foo
Connecting to 127.0.0.1:8080... connected.
HTTP request sent, awaiting response... 404 
2010-10-28 10:54:51 ERROR 404: (no description).

$ wget -O - http://127.0.0.1:8080/foo/
--2010-10-28 10:54:54--  http://127.0.0.1:8080/foo/
Connecting to 127.0.0.1:8080... connected.
HTTP request sent, awaiting response... 404 
2010-10-28 10:54:54 ERROR 404: (no description).

Если вы хотите вернуть более удобную страницу ошибки, следуйте совету jonmiddleton и укажите пользовательскую страницу 404.

person Nick Johnson    schedule 28.10.2010
comment
Это не работает таким образом, я думаю, что error_code может быть ^(default|over_quota|dos_api_denial|timeout)$, а по умолчанию НЕ обрабатывает ошибку 404 - person rafek; 28.10.2010
comment
@rafek Затем укажите универсальный обработчик, как предлагает Александр. В любом случае правильный код ответа уже возвращается обработчиками по умолчанию, просто без поясняющего сообщения для пользователей. - person Nick Johnson; 28.10.2010
comment
@Nick: если у меня есть обработчик /admin/.* и (все) обработчик /.* и я делаю то, что предлагает Александр .. тогда случай с domain.com/admin/stuff-that-doesnt-exist не обрабатывается .. coz Обработчик /admin/.* в app.yaml справляется с этим.. и тогда я должен был бы перехватывать все обработчики для каждого скрипта - это ужасное дублирование кода. - person rafek; 28.10.2010
comment
Затем ограничьте свои обработчики одним или создайте модуль, содержащий обработчик 404, который вы импортируете в каждый обработчик и устанавливаете в качестве универсального. - person Nick Johnson; 28.10.2010
comment
Один обработчик script - сколько угодно обработчиков. Большинство людей используют по одному на «приложение». - person Nick Johnson; 29.10.2010

Я рассмотрел все приведенные выше ответы и в конце использовал следующее как наиболее универсальное решение 404:

Добавьте эту ссылку в конце app.yaml

- url: /(.*) 
  script: 404.app

и создайте 404.py со следующим содержимым

import webapp2
from google.appengine.ext.webapp import template

class NotFound(webapp2.RequestHandler):
  def get(self):
    self.error(404)
    self.response.out.write(template.render('404.html', {}))

app = webapp2.WSGIApplication([
    ('/.*', NotFound)
], debug=True)

Это отобразит содержимое файла 404.html с кодом ошибки 404.

Преимуществом этого решения является простота, корректность поведения и гибкость, так как оно позволяет использовать статический 404.html файл в качестве содержимого страницы ошибок.

Я также хочу предостеречь от некоторых решений, предложенных выше.

  • Custom Error Responses не работает с ошибкой 404
  • Также не используйте статические файлы, так как они вернут ошибку 200 вместо ошибки 404. Это может вызвать много головной боли впереди.
person husayt    schedule 04.01.2016

Я не могу комментировать ответ jonmiddleton, но, судя по внешнему виду, пользовательские ответы на ошибки предназначены для конкретных ошибок движка приложения. Я не вижу способа указать пользовательскую страницу 404.

Django позволяет вам указать его.

person zahanm    schedule 01.03.2011

Мой подход состоит в том, чтобы обрабатывать как 404, так и постоянные перенаправления в обработчике улавливания всех, который я поставил последним. Это полезно, когда я изменяю дизайн и приложение, а также переименовываю/заменяю URL-адреса:

app = webapp2.WSGIApplication([
    ...
    ...
    ('/.*', ErrorsHandler)
], debug=True)


class ErrorsHandler(webapp2.RequestHandler):
    def get(self):
        p = self.request.path_qs
        if p in ['/index.html', 'resources-that-I-removed']:  
            return self.redirect('/and-substituted-with-this', permanent=True)
        else: 
            self.error(404)
            template = jinja_environment.get_template('404.html')
            context =  {
                'page_title': '404',
            }
            self.response.out.write(template.render(context))
person JackNova    schedule 13.06.2013