问题
I'm setting up a new server "LiteSpeed" , I am using Django 2.1.7 web framework every thing was good until i uploaded from admin a photo with a name contains Arabic letters
this image gives me an error
"The server encountered an unexpected condition which prevented it from fulfilling the request." so i review the server log and found that link throws an error
2019-06-09 00:26:17.429165 [ERROR] [2699022] wsgiHandler pApp->start_response() return NULL.
Traceback (most recent call last):
File "/home/qassimchalets/virtualenv/Py/3.7/lib/python3.7/site-packages/django/core/handlers/wsgi.py", line 139, in __call__
set_script_prefix(get_script_name(environ))
File "/home/qassimchalets/virtualenv/Py/3.7/lib/python3.7/site-packages/django/core/handlers/wsgi.py", line 179, in get_script_name
script_url = get_bytes_from_wsgi(environ, 'SCRIPT_URL', '') or get_bytes_from_wsgi(environ, 'REDIRECT_URL', '')
File "/home/qassimchalets/virtualenv/Py/3.7/lib/python3.7/site-packages/django/core/handlers/wsgi.py", line 204, in get_bytes_from_wsgi
return value.encode('iso-8859-1')
UnicodeEncodeError: 'latin-1' codec can't encode characters in position 23-26: ordinal not in range(256)
i have searched a lot with no good result so i changed this line return value.encode('iso-8859-1') with return value.encode('utf-8') in the core of the framework it works now for the link of the photo and other photos
I don't know if it will affect another things , as I changed in django handler core without any idea what this is really doing
class WSGIRequest(HttpRequest):
def __init__(self, environ):
script_name = get_script_name(environ)
# If PATH_INFO is empty (e.g. accessing the SCRIPT_NAME URL without a
# trailing slash), operate as if '/' was requested.
path_info = get_path_info(environ) or '/'
self.environ = environ
self.path_info = path_info
# be careful to only replace the first slash in the path because of
# http://test/something and http://test//something being different as
# stated in https://www.ietf.org/rfc/rfc2396.txt
self.path = '%s/%s' % (script_name.rstrip('/'),
path_info.replace('/', '', 1))
self.META = environ
self.META['PATH_INFO'] = path_info
self.META['SCRIPT_NAME'] = script_name
self.method = environ['REQUEST_METHOD'].upper()
self.content_type, self.content_params = cgi.parse_header(environ.get('CONTENT_TYPE', ''))
if 'charset' in self.content_params:
try:
codecs.lookup(self.content_params['charset'])
except LookupError:
pass
else:
self.encoding = self.content_params['charset']
self._post_parse_error = False
try:
content_length = int(environ.get('CONTENT_LENGTH'))
except (ValueError, TypeError):
content_length = 0
self._stream = LimitedStream(self.environ['wsgi.input'], content_length)
self._read_started = False
self.resolver_match = None
def _get_scheme(self):
return self.environ.get('wsgi.url_scheme')
@cached_property
def GET(self):
# The WSGI spec says 'QUERY_STRING' may be absent.
raw_query_string = get_bytes_from_wsgi(self.environ, 'QUERY_STRING', '')
return QueryDict(raw_query_string, encoding=self._encoding)
def _get_post(self):
if not hasattr(self, '_post'):
self._load_post_and_files()
return self._post
def _set_post(self, post):
self._post = post
@cached_property
def COOKIES(self):
raw_cookie = get_str_from_wsgi(self.environ, 'HTTP_COOKIE', '')
return parse_cookie(raw_cookie)
@property
def FILES(self):
if not hasattr(self, '_files'):
self._load_post_and_files()
return self._files
POST = property(_get_post, _set_post)
class WSGIHandler(base.BaseHandler):
request_class = WSGIRequest
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.load_middleware()
def __call__(self, environ, start_response):
set_script_prefix(get_script_name(environ))
signals.request_started.send(sender=self.__class__, environ=environ)
request = self.request_class(environ)
response = self.get_response(request)
response._handler_class = self.__class__
status = '%d %s' % (response.status_code, response.reason_phrase)
response_headers = list(response.items())
for c in response.cookies.values():
response_headers.append(('Set-Cookie', c.output(header='')))
start_response(status, response_headers)
if getattr(response, 'file_to_stream', None) is not None and environ.get('wsgi.file_wrapper'):
response = environ['wsgi.file_wrapper'](response.file_to_stream)
return response
def get_path_info(environ):
"""Return the HTTP request's PATH_INFO as a string."""
path_info = get_bytes_from_wsgi(environ, 'PATH_INFO', '/')
return repercent_broken_unicode(path_info).decode()
def get_script_name(environ):
"""
Return the equivalent of the HTTP request's SCRIPT_NAME environment
variable. If Apache mod_rewrite is used, return what would have been
the script name prior to any rewriting (so it's the script name as seen
from the client's perspective), unless the FORCE_SCRIPT_NAME setting is
set (to anything).
"""
if settings.FORCE_SCRIPT_NAME is not None:
return settings.FORCE_SCRIPT_NAME
# If Apache's mod_rewrite had a whack at the URL, Apache set either
# SCRIPT_URL or REDIRECT_URL to the full resource URL before applying any
# rewrites. Unfortunately not every Web server (lighttpd!) passes this
# information through all the time, so FORCE_SCRIPT_NAME, above, is still
# needed.
script_url = get_bytes_from_wsgi(environ, 'SCRIPT_URL', '') or get_bytes_from_wsgi(environ, 'REDIRECT_URL', '')
if script_url:
if b'//' in script_url:
# mod_wsgi squashes multiple successive slashes in PATH_INFO,
# do the same with script_url before manipulating paths (#17133).
script_url = _slashes_re.sub(b'/', script_url)
path_info = get_bytes_from_wsgi(environ, 'PATH_INFO', '')
script_name = script_url[:-len(path_info)] if path_info else script_url
else:
script_name = get_bytes_from_wsgi(environ, 'SCRIPT_NAME', '')
return script_name.decode()
def get_bytes_from_wsgi(environ, key, default):
"""
Get a value from the WSGI environ dictionary as bytes.
key and default should be strings.
"""
value = environ.get(key, default)
# Non-ASCII values in the WSGI environ are arbitrarily decoded with
# ISO-8859-1. This is wrong for Django websites where UTF-8 is the default.
# Re-encode to recover the original bytestring.
return value.encode('iso-8859-1')
I am really afraid of any non-expected behavior based on this change
just give me a good solution for that error as i think my solution will get more errors in future
回答1:
just used a technique to ensure that the file name or image name will be not containing any characters that will cause the problem
class City(models.Model):
name = models.CharField(max_length=100, verbose_name=_("City Name"),
validators=[RegexValidator(r'^[\u0621-\u064A\u0660-\u0669]+$')])
city_image = models.ImageField(upload_to='city/images/', blank=False, null=True, verbose_name=_("City Image"))
def save(self, force_insert=False, force_update=False, using=None,
update_fields=None):
name = self.city_image.name
extension = name.split('.')[-1]
for char in name:
if char not in 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.':
self.city_image.name = 'a' + '.' + extension
break
instance = super(City, self).save(force_insert=False, force_update=False, using=None,
update_fields=None)
来源:https://stackoverflow.com/questions/56511426/how-to-fix-error-2699022-wsgihandler-papp-start-response-return-null