# "UnicodeDecodeError: 'ascii' codec can't decode byte"

迁移了一个Django项目的Docker容器，发现运行存在问题，所以重建了`virtualenv`环境。多个Django项目中，其中有一个Django运行出现异常：

```
[20/Mar/2018 12:38:41] code 400, message Bad request syntax ('\x00\xf9\x02\x00\x0c\x00QUERY_STRING\x00\x00\x0e\x00REQUEST_METHOD\x03\x00GET
...
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/logging/__init__.py", line 861, in emit
    msg = self.format(record)
  File "/usr/local/lib/python2.7/logging/__init__.py", line 734, in format
    return fmt.format(record)
  File "/data/myapp_admin/venv2/lib/python2.7/site-packages/django/utils/log.py", line 192, in format
    return super(ServerFormatter, self).format(record)
  File "/usr/local/lib/python2.7/logging/__init__.py", line 476, in format
    raise e
UnicodeDecodeError: 'ascii' codec can't decode byte 0xf9 in position 9: ordinal not in range(128)
```

这个问题看上去像是客户端请求中包含了Unicode字符，但是服务器端恢复`virtualenv`环境没有支持？

google了一些文档，发现很多都指向了http请求中出现https，原因和nginx反向`uwsgi_pass`给Django有关，似乎是客户端试图以`https`访问`http`导致的问题。 - 参考 [strange UnicodeDecodeError on django](https://stackoverflow.com/questions/18940441/strange-unicodedecodeerror-on-django)

检查了nginx配置：

```
upstream django_perfree {
    server 127.0.0.1:8080;
}

server {
    listen      80;
    server_name myapp.example.com;
    charset     utf-8;
    client_max_body_size 75M;
    location /media  {
        alias /home/admin/perfree/media;
    }
    location /static {
        alias /home/admin/perfree/static;
    }
```

## HAProxy

然而，在检查访问链路的时候，发现了一些和线上不同的区别：

* 虽然nginx配置和线上相似，但是线上环境是直接访问 nginx 反向代理到后端 `uwsgi` 运行的 `8080` 端口
* 线下开发环境是自己搭建的Docker环境，但是为了模拟复杂的网络环境，并且能够运行不同的测试环境，我采用了Docker来运行测试机，而且将Docker所在的主机放置在一台运行了HAProxy的主机（`gw-1`）之后再连接到局域网：
  * 模拟前端有防火墙的Internet服务，在`gw-1`上启用了Ubuntu UFW（[使用ufw配置NAT masquerade](https://github.com/huataihuang/cloud-atlas-draft/tree/6f3204fffc11cf006abd394631e2598d98b415c3/os/linux/network/firewall/ufw/nat_masquerade_in_ufw/README.md)）
  * `gw-1`上使用HAProxy反向代理到`svr-1`上运行的Docker容器映射端口

```
listen mydjango
    bind 192.168.44.11:80
    mode tcp
    balance roundrobin
    server mydjango-1 192.168.0.2:80 check
```

[Haproxy Charset](https://pleasantprogrammer.com/posts/haproxy-charset.html) 似乎说明HAProxy实际上默认使用UTF-8作为文本存储和渲染。

暂时停止`gw-1`上HAProxy，然后暂时使用ufw端口映射来替代这个反向代理。编辑`/etc/ufw/before.rules`添加到

```
# nat Table rules
*nat
:PREROUTING ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]

...
-A PREROUTING -i wlp3s0 -p tcp --dport 80 -j DNAT --to-destination 192.168.0.2
```

但是发现使用ufw直接转发HTTP访问（没有使用HAProxy）依然出现同样的报错信息。看来，不是HAProxy代理的原因。

## 暂时绕开

由于不经过nginx反向代理，直接访问Django 8080端口是可以正常工作，所以修改docker，重建端口映射，直接将Docker 8001端口映射给Django 8001端口来运行应用。

```
docker commit myapp local:myapp
docker stop myapp
docker rm myapp

docker run -it -p 221:22 -p 801:80 -p 4431:443 -p 8081:8080 -p 33061:3306 --hostname myapp \
--name myapp -v share-data:/data local:myapp /bin/bash
```

然后在防火墙`gw-1`上修改映射

```
-A PREROUTING -i wlp3s0 -p tcp --dport 8081 -j DNAT --to-destination 192.168.0.2
```

暂时绕过nginx反向代理到Django端口运行到问题，采用直接访问Django 8080端口来测试。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://huataihuang.gitbook.io/cloud-atlas-draft/develop/python/django/debug/unicode_decode_error.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
