jenkins 插件乱码处理与文件上传

2020/9/28

同事反馈使用插件 https://github.com/jenkinsci/pipeline-model-definition-plugin 组织请求 Information on extending/integrating with Pipeline Model Definition 时出现乱码。

Investigation

搭建环境复现问题

  1. 拉取 jenkins/jenkins 镜像
  2. Pipeline: Declarative 安装插件 pipeline-model-definition.hpi
  3. 组织请求,问题复现

使用搜索,推测乱码编码为 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 原创,转载请注明来自博客园

原文地址:https://www.cnblogs.com/leoninew/p/13747920.html