问题
I'm trying to setup python on A2 shared hosting via passenger_wsgi. The app is working fine when I run it via 'runserver'. I tested this both in my local PC, and via SSH tunnel.
However, when I try to set this up on passenger_wsgi, it can't seem to be able to route POST request.
1 import os
2 import sys
3
4 sys.path.insert(0, "/home/<username>/app")
5
6 import APP_CORE
7
8 # where is the python interpreter
9 INTERP = "/home/<username>/app/.virtualenv/bin/python"
10 if sys.executable != INTERP: os.execl(INTERP, INTERP, *sys.argv)
11
12
13 os.environ['DJANGO_SETTINGS_MODULE'] = "APP_CORE.settings"
14
15 import APP_CORE.wsgi
16 application = APP_CORE.wsgi.application
Example: when I load the admin page (/admin/login), it can load the login page, but when submitting the credentials, it says that POST to /admin/login is not found - returning HTTP 404.
The SAME flow when I run via runserver works - I feel that I could be missing something in the django WSGI configuration. Any help would be appreciated !!
Edit/update: After diving into resolver.py and base.py:_get_response, I've noticed that somehow the /path/info truncates the first bit of the URL. Example, when I am requesting for /admin/login/, the path info only shows /login - but when I am using runserver, it is properly passed thru as /admin/login. To me this is clearly the issue on the web server setup and not on the django site. So will try to work it out with A2Hosting...
回答1:
It looks like you may have solved this, but to followup for anyone that may stumble here. I have been using A2Hosting, Passenger, and CPanel with django (and wagtail). What I found was that during POST requests the wsgi SCRIPT_NAME
was being set to a relative path and not the root of the application.
When I added logging to each application call, the correct GET
request was:
{
'REQUEST_URI': '/admin/',
'PATH_INFO': '/admin/',
'SCRIPT_NAME': '',
'QUERY_STRING': '',
'REQUEST_METHOD': 'GET',
...
But on that page, a form was submitting a POST
, which had the PATH_INFO
incorrectly set:
{
'REQUEST_URI': '/admin/login/',
'PATH_INFO': '/login/',
'SCRIPT_NAME': '/admin',
'QUERY_STRING': '',
'REQUEST_METHOD': 'POST',
...
The workaround I ended up using was to create middleware which asserted a known SCRIPT_NAME
and rebuilt the PATH_INFO
from it.
# Set this to your root
SCRIPT_NAME = ''
class PassengerPathInfoFix(object):
"""
Sets PATH_INFO from REQUEST_URI since Passenger doesn't provide it.
"""
def __init__(self, app):
self.app = app
def __call__(self, environ, start_response):
from urllib.parse import unquote
environ['SCRIPT_NAME'] = SCRIPT_NAME
request_uri = unquote(environ['REQUEST_URI'])
script_name = unquote(environ.get('SCRIPT_NAME', ''))
offset = request_uri.startswith(script_name) and len(environ['SCRIPT_NAME']) or 0
environ['PATH_INFO'] = request_uri[offset:].split('?', 1)[0]
return self.app(environ, start_response)
application = get_wsgi_application()
application = PassengerPathInfoFix(application)
Related Reading:
- http://alyalearningdjango.blogspot.com/2014/05/issue-360-passenger-doesnt-set-pathinfo.html
- https://github.com/phusion/passenger/issues/460
- https://www.python.org/dev/peps/pep-0333/#environ-variables
来源:https://stackoverflow.com/questions/49594955/django-1-11-on-passenger-wsgi-not-routing-post-request