I'm trying to run a simple "hello world" application using mod_wsgi for Python 3. I'm using Fedora 23. Here's my Apache virtual host configuration:
<VirtualHost *:80>
    ServerName localhost
    ServerAdmin admin@localhost
    # ServerAlias foo.localhost
    WSGIScriptAlias /headers /home/httpd/localhost/python/headers/wsgi.py
    DocumentRoot /home/httpd/localhost/public_html
    ErrorLog /home/httpd/localhost/error.log
    CustomLog /home/httpd/localhost/requests.log combined
</VirtualHost>
wsgi.py:
def application(environ, start_response):
    status = '200 OK'
    output = 'Hello World!'
    response_headers = [('Content-Type', 'text/plain'),
                        ('Content-Length', str(len(output)))]
    start_response(status, response_headers)
    return [output]
It works fine if I use mod_wsgi for Python 2 (sudo dnf remove python3-mod_wsgi -y && sudo dnf install mod_wsgi -y && sudo apachectl restart), but I get a 500 internal server error when using Python 3. Here's the error log:
mod_wsgi (pid=899): Exception occurred processing WSGI script '/home/httpd/localhost/python/headers/wsgi.py'.
TypeError: sequence of byte string values expected, value of type str found
Update
Using encode() (or encode('utf-8')) on str(len(output)) isn't working either. Now I get:
Traceback (most recent call last):
  File "/home/httpd/localhost/python/headers/wsgi.py", line 8, in application
    start_response(status, response_headers)
TypeError: expected unicode object, value of type bytes found
                Apparently the variable output itself needs to have a bytes string rather than a unicode string. And it needs to change not only for response_headers, but for everywhere output is used (so str(len(output)).encode('utf-8') on line 6 wouldn't work, like I'd been trying).
So the solution in my case is:
def application(environ, start_response):
    status = '200 OK'
    output = b'Hello World!'
    response_headers = [('Content-type', 'text/plain'),
                        ('Content-Length', str(len(output)))]
    start_response(status, response_headers)
    return [output]
(which I found in one of the tests on the official mod_wsgi repo, as suggested by Rolbrok in comments.)
Background
The issue is caused because Python 3 defaulted UTF-8, because today, we find that there is a lot of non native English characters, and it is best to accommodate them. HTTP works only with ASCII characters. It does not handle UTF-8 well. Hence, neither Apache,nor mod_wsgi works well with UTF 8.
Solution
So, after you prepare the entire html string, you can typecast it using the inbuilt python function - bytes(). This takes a string and gives a byte string.
Sample Code
html = "This "
html += "is the code"
html = bytes(html, encoding= 'utf-8')
response_header = [('Content-type', 'text/html')]
start_response(status, response_header)
yield html
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With