在Django中捕获错误的%编码的URL以返回自定义的“错误400”页面

时间:2022-04-29 23:19:10

Sometimes, other websites use incorrectly percent-encoded URLs to link to our Django powered site. Disqus.com and Twitter.com do have the same issue, so it's nothing special about our use case: http://disqus.com/%C3A4. In this URL, a second % is missing. The valid URL looks like this: http://disqus.com/%C3%A4

有时,其他网站使用错误的百分比编码的URL链接到我们的Django支持的站点。 Disqus.com和Twitter.com也有同样的问题,所以我们的用例没有什么特别之处:http://disqus.com/%C3A4。在此URL中,缺少第二个%。有效的URL如下所示:http://disqus.com/%C3%A4

Django returns an empty error 400 (Bad request) page. However, we'd like to catch the error, and instead of returning a plain non-informative page, we'd like to show our users at least our custom 404 page. Better even, we'd like to check the input URL on missing %-characters or anything alike to validate its format. MiddleWare/process_request gets called even with our present 400-errors, so we do have a hook to catch the error.

Django返回一个空错误400(错误请求)页面。但是,我们想要捕获错误,而不是返回一个简单的非信息页面,我们想向用户显示至少我们的自定义404页面。甚至更好,我们想检查缺少%-characters或类似内容的输入URL以验证其格式。即使使用我们当前的400错误,也会调用MiddleWare / process_request,因此我们确实有一个钩子来捕获错误。

We'd like to address the issue on our site. Is there any best practice ...? A handler400 would be great - is it possible to create one on your own?

我们想在我们的网站上解决这个问题。有没有最好的做法......?处理程序400会很棒 - 是否可以自己创建一个?

2 个解决方案

#1


1  

Create 404.html in your template then put this in your urls.py

在模板中创建404.html,然后将其放入urls.py中

#handle the errors    
from django.utils.functional import curry
from django.views.defaults import *

handler404 = curry(page_not_found, template_name='404.html')

You can also handle other errors like this:
handler500 = curry(server_error, template_name='500.html')
handler403 = curry(permission_denied, template_name='403.html')

Handles any type of errors. You will get an idea here.

处理任何类型的错误。你会在这里得到一个想法。

https://github.com/Roejames12/django-error-pages

#2


0  

As posted already in form of a comment in Cathy's aswer that is really good, but doesn't work in this particular case, I publish our current, slightly hackish solution here as another answer:

已经以Cathy's aswer中的评论形式发布,这是非常好的,但在这个特殊情况下不起作用,我在这里发布我们当前的,稍微有点hackish的解决方案作为另一个答案:

Apparently, this error cannot be overridden inside Django's MiddleWares. It's a UNICODE decode error that is triggered inside WSGIHandler in \django\core\handlers\wsgi.py. To be precise, it is

显然,这个错误无法在Django的MiddleWares中被覆盖。这是在\ django \ core \ handlers \ wsgi.py中的WSGIHandler内触发的UNICODE解码错误。确切地说,确实如此

path_info = force_unicode(environ.get('PATH_INFO', u'/'))

inside WSGIRequest, which is causing the issue. It's basically correct behavior by Django, but as described in my question, we simply want to show our users something more useful, than an empty error page. Therefore, we check incoming URL requests upon valid UNICODE characters before passing them on to our WSGIHandler. This blog post pointed us into the right direction: http://codeinthehole.com/writing/django-nginx-wsgi-and-encoded-slashes/

在WSGIRequest中,导致问题。这是Django基本上正确的行为,但正如我的问题中所描述的,我们只想向用户展示比空错误页面更有用的东西。因此,在将有效UNICODE字符传递给我们的WSGIHandler之前,我们会检查传入的URL请求。这篇博客文章指出了我们正确的方向:http://codeinthehole.com/writing/django-nginx-wsgi-and-encoded-slashes/

Thus, we reroute invalid URLs inside our wsgi.py like so:

因此,我们在wsgi.py中重新路由无效的URL,如下所示:

os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'

import django.core.handlers.wsgi
_application = django.core.handlers.wsgi.WSGIHandler()

# for Django 1.7+
# from django.core.wsgi import get_wsgi_application
# _application = get_wsgi_application()

from django.utils.encoding import force_unicode
def application(environ, start_response):
    try:
        path_info = force_unicode(environ.get('PATH_INFO', u'/'))
    except:
        environ['PATH_INFO'] = u'/'
    return _application(environ, start_response)

Subclassing WSGHandler instead, should also work. In this example, we simply redirect invalid URLs to our site root "/". But you could also redirect to any custom error page URL, or you could try sanitizing your URL ... It works for us, but maybe there's a better solution out there.

相反,对WSGHandler进行子类化也应该有效。在此示例中,我们只是将无效网址重定向到我们的网站根“/”。但您也可以重定向到任何自定义错误页面网址,或者您可以尝试清理您的网址...它适用于我们,但也许有更好的解决方案。

#1


1  

Create 404.html in your template then put this in your urls.py

在模板中创建404.html,然后将其放入urls.py中

#handle the errors    
from django.utils.functional import curry
from django.views.defaults import *

handler404 = curry(page_not_found, template_name='404.html')

You can also handle other errors like this:
handler500 = curry(server_error, template_name='500.html')
handler403 = curry(permission_denied, template_name='403.html')

Handles any type of errors. You will get an idea here.

处理任何类型的错误。你会在这里得到一个想法。

https://github.com/Roejames12/django-error-pages

#2


0  

As posted already in form of a comment in Cathy's aswer that is really good, but doesn't work in this particular case, I publish our current, slightly hackish solution here as another answer:

已经以Cathy's aswer中的评论形式发布,这是非常好的,但在这个特殊情况下不起作用,我在这里发布我们当前的,稍微有点hackish的解决方案作为另一个答案:

Apparently, this error cannot be overridden inside Django's MiddleWares. It's a UNICODE decode error that is triggered inside WSGIHandler in \django\core\handlers\wsgi.py. To be precise, it is

显然,这个错误无法在Django的MiddleWares中被覆盖。这是在\ django \ core \ handlers \ wsgi.py中的WSGIHandler内触发的UNICODE解码错误。确切地说,确实如此

path_info = force_unicode(environ.get('PATH_INFO', u'/'))

inside WSGIRequest, which is causing the issue. It's basically correct behavior by Django, but as described in my question, we simply want to show our users something more useful, than an empty error page. Therefore, we check incoming URL requests upon valid UNICODE characters before passing them on to our WSGIHandler. This blog post pointed us into the right direction: http://codeinthehole.com/writing/django-nginx-wsgi-and-encoded-slashes/

在WSGIRequest中,导致问题。这是Django基本上正确的行为,但正如我的问题中所描述的,我们只想向用户展示比空错误页面更有用的东西。因此,在将有效UNICODE字符传递给我们的WSGIHandler之前,我们会检查传入的URL请求。这篇博客文章指出了我们正确的方向:http://codeinthehole.com/writing/django-nginx-wsgi-and-encoded-slashes/

Thus, we reroute invalid URLs inside our wsgi.py like so:

因此,我们在wsgi.py中重新路由无效的URL,如下所示:

os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'

import django.core.handlers.wsgi
_application = django.core.handlers.wsgi.WSGIHandler()

# for Django 1.7+
# from django.core.wsgi import get_wsgi_application
# _application = get_wsgi_application()

from django.utils.encoding import force_unicode
def application(environ, start_response):
    try:
        path_info = force_unicode(environ.get('PATH_INFO', u'/'))
    except:
        environ['PATH_INFO'] = u'/'
    return _application(environ, start_response)

Subclassing WSGHandler instead, should also work. In this example, we simply redirect invalid URLs to our site root "/". But you could also redirect to any custom error page URL, or you could try sanitizing your URL ... It works for us, but maybe there's a better solution out there.

相反,对WSGHandler进行子类化也应该有效。在此示例中,我们只是将无效网址重定向到我们的网站根“/”。但您也可以重定向到任何自定义错误页面网址,或者您可以尝试清理您的网址...它适用于我们,但也许有更好的解决方案。