一、问题

在用jekyll-tagging做标签时,使用中文标签会出现在标签页面点击其他中文标签链接找不到文件的问题,如下图所示:

直接用中文命名文章也会有此问题。

二、分析

仔细观察上图,可以看到从tag目录下点击’爱情.html’和在页面点击’爱情.html’在浏览器中的地址不一样,所以应该是文件名编码的问题。\

使用java的URLEncoder.encode方法分别使用GBKUTF-8对’爱情’编码:

String str = "爱情";
System.out.println(URLEncoder.encode(str, "GBK"));//%B0%AE%C7%E9
System.out.println(URLEncoder.encode(str, "UTF-8"));//%E7%88%B1%E6%83%85

可以看到,使用GBK编码的结果和直接访问tag目录下’爱情.html’在浏览器中显示的一致;

再看下在标签页面中生成的标签的链接地址,例如’爱情’标签是:/tag/%E7%88%B1%E6%83%85.html,此值和上面对’爱情’使用UTF-8编码的结果一致;在浏览器中访问localhost:8080/tag/%E7%88%B1%E6%83%85.html,在地址栏中看到的是’localhost:8080/tag/爱情.html’,浏览器地址栏在显示时应该会对UTF-8编码的中文自动转换。

1、文件内容编码格式

上网搜到的都是说文件内容编码格式的问题,官网文档中也提到过_config.yml中的encoding配置:

  • encoding: ENCODING

设置文件的编码,仅 Ruby 1.9 以上可用。2.0.0 版本以后默认值为 utf-8,之前版本默认值为 nil,使用 Ruby 默认的 ASCII-8BIT。
可以用命令 ruby -e 'puts Encoding::list.join("\n")' 查看 Ruby 可用的编码。

2、文件名编码格式

找了好久资料,但没有找到文件名编码格式问题的答案。于是想着找找源码,看能不能找到解决方法:

ruby的安装目录下lib\ruby\2.4.0\webrick\httpservlet\filehandler.rb文件中可以看到访问tag目录时构造响应内容HTML的过程,其中它对tag目录下显示的文件名使用了HTTPUtils.escape方法处理

s =  "<TR><TD class=\"name\"><A HREF=\"#{HTTPUtils::escape(name)}#{query if name.end_with?('/')}\">#{HTMLUtils::escape(dname)}</A></TD>"
s << "<TD class=\"mtime\">" << (time ? time.strftime("%Y/%m/%d %H:%M") : "") << "</TD>"
s << "<TD class=\"size\">" << (size >= 0 ? size.to_s : "-") << "</TD></TR>\n"

增加日志查看编码信息:

logger = Logger.new(STDOUT)
logger.info(Encoding.find("filesystem"))
logger.info("name: #{name.encoding}")

Encoding.find("filesystem"):The default encoding of strings from the filesystem of the environment. This is used for strings of file names or paths.

输出:

#<Encoding:GBK>
name: GBK

可以看到文件系统对路径和文件名字符串默认的编码为GBK,输出的name的编码确实为GBK

之后使用force_encoding(encoding)encode(dst_encoding, src_encoding [, options])转为UTF-8编码格式的字符串时会出现乱码问题。

后来又查了下,据说使用Iconv能转换编码,于是使用gem install iconv安装,但提示又需要安装MSYS2,按http://www.msys2.org/中的步骤在最后Update时未成功。

三、结果

此问题并未解决,但将生成的内容在nginx下测试正常。

由于对ruby不熟悉,所以暂时只能这样了,如果哪位大神有解决方法请发邮件(albertbamboo@foxmail.com)告知,感激不尽!

四、其他

  • irb

在命令行下输入:irb 即可开启交互式shell.

  • ruby xxx.rb

执行ruby文件

  • puts

输出内容并自动换行,如果有转义字符,则先转义再输出

  • print

puts相同,但不会自动换行

  • open-uri
require 'open-uri'

name = open('G:/name.txt'){
	|file|  file.read
}

puts "name: #{name}"
参考资料