Django Apache SSL [代码 400,消息错误请求]

Posted

技术标签:

【中文标题】Django Apache SSL [代码 400,消息错误请求]【英文标题】:Django Apache SSL [code 400, message bad request] 【发布时间】:2015-03-08 14:34:05 【问题描述】:

我对 Apache 代理 Web 服务器和 Django SSL 有疑问,以下是 SSL 的 Django settings.py 和 apache server.conf 文件后出现的错误,django 版本 1.6.8

  ----------------------------------------
  [10/Jan/2015 09:11:33] code 400, message Bad request syntax ('\x16\x03\x00\x00?
  Exception happened during processing of request from ('5.5.0.46', 38141)
  Traceback (most recent call last):
  File "/usr/lib/python2.7/SocketServer.py", line 593, in process_request_thread
   self.finish_request(request, client_address)
  File "/usr/lib/python2.7/SocketServer.py", line 334, in finish_request
   self.RequestHandlerClass(request, client_address, self)
  File "/usr/local/lib/python2.7/dist-packages/django/core/servers/basehttp.py", line 126, in __init__
   super(WSGIRequestHandler, self).__init__(*args, **kwargs)
  File "/usr/lib/python2.7/SocketServer.py", line 649, in __init__
   self.handle()
  File "/usr/lib/python2.7/wsgiref/simple_server.py", line 117, in handle
   if not self.parse_request(): # An error code has been sent, just exit
  File "/usr/lib/python2.7/BaseHTTPServer.py", line 286, in parse_request
    self.send_error(400, "Bad request syntax (%r)" % requestline)
  File "/usr/lib/python2.7/BaseHTTPServer.py", line 368, in send_error
    self.send_response(code, message)
  File "/usr/lib/python2.7/BaseHTTPServer.py", line 385, in send_response
    self.log_request(code)
  File "/usr/lib/python2.7/BaseHTTPServer.py", line 422, in log_request
    self.requestline, str(code), str(size))
  File "/usr/local/lib/python2.7/dist-packages/django/core/servers/basehttp.py", line 138, in log_message
   msg = "[%s] %s\n" % (self.log_date_time_string(), format % args)
  UnicodeDecodeError: 'ascii' codec can't decode byte 0xf9 in position 12: ordinal not in    range(128)
  ----------------------------------------

settings.py

   ...... 

   # secure proxy SSL header and secure cookies
   SECURE_SSL_REDIRECT = True
   SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
   SESSION_COOKIE_SECURE = True
   CSRF_COOKIE_SECURE = True

   # session expire at browser close
   SESSION_EXPIRE_AT_BROWSER_CLOSE = True

   # wsgi scheme
   os.environ['wsgi.url_scheme'] = 'https'
   ......

apache server.conf

 <IfModule mod_ssl.c>
    <VirtualHost *:80>
            ServerName mywebsite.com
            WSGIScriptAlias / /var/www/manage/manage/wsgi.py
    </VirtualHost>
    <VirtualHost _default_:443>
            ServerName mywebsite.com
            WSGIScriptAlias / /var/www/manage/manage/wsgi.py
            SSLEngine on
            SSLCertificateFile      /etc/apache2/ssl/apache.crt
            SSLCertificateKeyFile /etc/apache2/ssl/apache.key
            redirect permanent / https://5.5.0.38:8080
    </VirtualHost>
  </IfModule>

我还在 django wsgi.py

中启用了 HTTPS
  ......
  os.environ['HTTPS'] = "on"
  ..............

【问题讨论】:

【参考方案1】:

错误的请求语法('\x16\x03\x00\x00?

这是预期 HTTP 流量的 HTTPS 流量。我认为这是由您的 apache.conf 中的以下行引起的:

redirect permanent / https://5.5.0.38:8080

这会指示浏览器访问给定的 URL(可能是您的 Django 服务器)。它不会将请求转发到 Django 服务器(您可能想要这样做),而是指示浏览器发出新请求并直接从 Django 服务器获取资源,即前面没有 apache。如果您想在另一台服务器前使用 apache,我认为您需要使用 ProxyPass 或 ProxyPassReverse 之类的东西。

如果 8080 端口实际用于 https 将是非常不寻常的,通常这仅用于 http。因此,我假设您的 Django 服务器本身只是在说普通的 http。

os.environ['HTTPS'] = "on"

这不会使 Django 成为 HTTPS 服务器,但它只是指示 Django 将所有链接创建为 https 链接。这支持了我的假设,即您的 Django 服务器本身只执行普通的 http。

【讨论】:

我需要将 HTTPS 请求从 apache 服务器重定向到 Django 服务器,并将它们返回到同一个端口 443 好的,在启用 proxy_http 模块并将 Proxypas-s-reverse 添加到 proxy.conf 文件后,它可以工作,但是我在获取 js/css/和图像文件等资源时遇到问题 无法加载资源:服务器响应状态为 502(代理错误),所以我怎样才能保持所有请求运行并获取所有资源而不会收到此错误消息 谢谢,在查看了 proxy.conf 文件后,我修改了 ProxyPassReverse / 5.5.0.38:8080 而不是 ProxyPassReverse / 5.5.0.38:8080,斜线 '/' 会导致此错误 @AhmedAbdullah django 服务器是否在内部使用 apache 服务器?或者我在哪里可以找到这个 .conf 文件?【参考方案2】:

我认为正确的答案如下:

首先启用 apache 的 proxy_http 模块将 url 从 https 重新映射到 http

$ a2enmod proxy_http

第二个去掉https请求到django的重定向

添加 ProxyPass 和 ProxyPassReverse 以通过 http 协议将 https 请求从 apache 服务器传递到 Django

以下是我为 apache.conf 所做的

    <VirtualHost *:80>
            ServerName mywebsite.com
            WSGIScriptAlias / /var/www/manage/manage/wsgi.py
    </VirtualHost>
    <VirtualHost _default_:443>
            ServerName mywebsite.com
            WSGIScriptAlias / /var/www/manage/manage/wsgi.py
            SSLEngine on
            SSLCertificateFile      /etc/apache2/ssl/apache.crt
            SSLCertificateKeyFile /etc/apache2/ssl/apache-wp.key
            ProxyPass / http://myip:8080/
            ProxyPassReverse / http://myip:8080/
            #redirect permanent / https://myip:8080
    </VirtualHost>

还要确保将所有 http 重写为 https 编辑 /etc/apache2/sites-enabled/000-default.conf apache 文件,如下所示

<VirtualHost *:80>
        ServerAdmin webmaster@localhost
        DocumentRoot /var/www/html
        RewriteEngine On
        RewriteCond %HTTPS !on
        RewriteRule (.*) https://%HTTP_HOST%REQUEST_URI
        ErrorLog $APACHE_LOG_DIR/error.log
        CustomLog $APACHE_LOG_DIR/access.log combined
</VirtualHost>

【讨论】:

以上是关于Django Apache SSL [代码 400,消息错误请求]的主要内容,如果未能解决你的问题,请参考以下文章

使用 Apache/NginX 部署时出现 Django Bad Request(400) 错误

使用 SSL 在 apache 上运行 django 应用程序:pexpect spawn/expect 不起作用

Apache https 重定向导致 400 错误

Django网站(Apache部署)安装Let's Encrypt免费SSL证书

SSL:400 没有发送所需的证书

django关闭debug后,报400错误