2020/9/28
同事反馈使用插件 https://github.com/jenkinsci/pipeline-model-definition-plugin 组织请求 Information on extending/integrating with Pipeline Model Definition 时出现乱码。
Investigation
搭建环境复现问题
- 拉取 jenkins/jenkins 镜像
- 从 Pipeline: Declarative 安装插件 pipeline-model-definition.hpi
- 组织请求,问题复现
使用搜索,推测乱码编码为 ISO-8859-1,
No matter how you set a form‘s charset,Tomcat always treats it by iso 8859-1.So what we read from the input strem are 8859-1 encoded.
var bytes= Encoding.UTF8.GetBytes("汉字");
Encoding.GetEncoding("ISO-8859-1").GetString(bytes).Dump();
?±??-?
Solution
在检查修改 jenkins 相关设置、更新环境变量之后,情况照旧。回头继续阅读相关页面。
看起来将 jenkinsfile 以 multipart/form-data 上传在 tomcat 和 jetty 会产生编码问题,尝试切换 content-type 到 application/x-www-form-urlencoded 后,乱码消失。
Further more
在最初的 HTTP 协议中,并没有上传文件方面的功能,RFC1867 为 http协议添加了这个能力。回想到早期 WCF REST 相关开发工作期间,我们并没有 HttpClient 这些实现,对照协议模拟表单提交时,有注意到频繁的编码设置,参考 HTTP协议之multipart/form-data
http请求中的 multipart/form-data,它会将表单的数据处理为一条消息,以标签为单元,用分隔符分开。既可以上传键值对,也可以上传文件。当上传的字段是文件时,会有 content-type来表名文件类型;content-disposition,用来说明字段的一些信息;
由于有 boundary隔离,所以 multipart/form-data 既可以上传文件,也可以上传键值对,它采用了键值对的方式,所以可以上传多个文件。
前文中的用法,会使 jenkinsfile 的 pipline 被以"文件内容"编码,故问题出现在"文件内容"解析上。故推测 POSTMAN 的 multipart/form-data 表示无法提供完整的参数控制。
查看 Fiddler 抓取到的请求头。
可以看到没有设置 content-type,现在使用 LINQPad 编写代码进行请求
var jenkinsfile = @"pipeline {
agent any
stages {
stage(‘Stage 1‘) {
steps {
echo ‘Hello world 汉字‘
}
}
}
}";
var client = new HttpClient();
var content = new MultipartFormDataContent();
content.Add(new StringContent(jenkinsfile, Encoding.UTF8), "jenkinsfile");
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", "YWRtaW46YWRtaW4=");
var resp = await client.PostAsync("http://localhost:8080/pipeline-model-converter/toJson", content);
resp.EnsureSuccessStatusCode();
var respText = resp.Content.ReadAsStringAsync();
Console.WriteLine(respText);
请求返回了正确的响应,抓取和查看生成的请求头如下
可以看到与 Postman 相比多出了 content-type 参数,重新回顾模拟过程
var bytes= Encoding.UTF8.GetBytes("汉字");
Encoding.GetEncoding("ISO-8859-1").GetString(bytes).Dump();
?±??-?
Summary
我们使用 UTF-8 编写了 pipline,然而使用 Postman 的发送过程丢失了编码格式,最终被 jenkins/jetty 以 ISO-8859-1 解析,于是乱码出现,使用 multipart/form-data 时携带文件编码即可规避,至此问题解决。"君子性非异也,善假于物也",如今各种开发工具极大地方便了广大程序员群体,但是熟知协议类仍然有十足的意义。
leoninew 原创,转载请注明来自博客园