Windows平台上在使用Nginx的时候无法支持中文路径,哪怕是直接访问一个中文路径,也无法访问到,访问文件是404,访问目录是500。
解决方案思考
正常情况下先访问一个内部有中文文件或目录的目录,Nginx会显示为乱码(调整网页编码能正确),而且其中的链接是直接编码的,什么意思,就是这个链接是GBK字符集的URL编码,所以肯定是访问不了的了。不过即使手动将链接改为UTF-8字符集的URL编码,也依然访问不了。
基于上面的一些现象和实际情况分析,基本可获得以下结论
- 输出必须是UTF-8编码的网页,特别是URL链接
- 内部本地系统是GBK编码,必须把请求路径最终转换成本地字符编码
当然,在Linux等系统上搞定字符集很简单,Win32就很难了,基本没有成功的可能性,不过网络上提供了一些解决该问题的方法,比如添加 charset gbk,utf-8;
,确实是页面能显示中文了,但是并不能下载,原因同上。
修改源码实现
思索再三,发现还是只能去修改源码了,既然是字符集的对应关系,那么就是需要将本地和UTF-8字符集进行转换,增加这么一层逻辑不就可以了么。其中目录浏览功能是个文件遍历功能,这个咱很熟悉,在Win上就是 FindFirstFile
系列函数,看源码,在 http\modules\ngx_http_autoindex_modele.c
文件中 ngx_http_autoindex_handler
函数中有详细的逻辑,基本是2个函数 ngx_open_dir
和 ngx_read_dir
,看实现确实和我们想象的是一致的。
首先看一下具体的定义吧,其中外部统一的定义结构体是 ngx_dir_t
typedef struct { |
里面使用的是ANSI版本的API,如果依然要使用该版本的API,那么就需要修改输入和输出了,也就是在 ngx_open_dir
函数内把字符集从UTF-8转为本地字符集,然后在 ngx_read_dir
函数里面再将字符集转成UTF-8,转什么字符集呢,从源码中可以看到,主要是 WIN32_FIND_DATA
结构体里面的 cFileName
,不过在Windows上转换字符集非常麻烦,竟然没有一步到位的,比如要将本地转UTF-8的步骤是先把本地转UTF-16,然后再转UTF-8,需要2步,此处我打算使用宽字符版进行。
首先,在 ngx_dir_t
类型中增加一个宽字符版本的结构体
WIN32_FIND_DATAW finddataw; |
为什么是增加呢,而不是直接修改呢,因为在输出的时候还需要转换!
然后在 ngx_open_dir
里面实现,大概如下
ngx_int_t |
然后在 ngx_read_dir
里面实现,如下
ngx_int_t |
基本想法就是使用宽字符版的API,然后将结果转为多字节版,这个转换函数实现如下
static void ngx_win32_find_data_w2a(WIN32_FIND_DATAW* w, WIN32_FIND_DATAA* a) { |
显示字符集调整
上面的修改基本搞定了目录浏览功能,但是还有个小问题,浏览器并没有自动的使用UTF-8,每次都要手动在浏览器上选择字符编码,很麻烦,因为我们已经确定了字符集,只需要在代码写死即可。
在文件 http\modules\ngx_http_autoindex_modele.c
文件实现如下
static ngx_buf_t * |
就是简单增加了一个 <meta>
标记。
下载试用
本来不想放的,不过总有人图省事,不想自己编译的话,就直接拿我编译的试用吧
NGINX 1.9.11 32位,VC2017编译 https://pan.baidu.com/s/1I1fWvW7wVOB7pEmoVoj_xA