一、问题提出
近期,由于与另一PHP程序之间,动态传递JSON数据,使用delphi XE10.4中idhttp控件实施。代码完成,出现三个问题:
1、JSON文本定长自动加入“=”;
2、英文和数字显示正常,中文显示为“????”;
3、Post反馈的信息中,如有汉字不能显示。
二、问题探索
1、通过生成UTF8格式文件,再导入上传,显示的汉字不是“????”,而是乱码了。
StringStream := TStringStream.Create('', TEncoding.UTF8);
StringStream.WriteString(Json1.ToString);
StringStream.SaveToFile(FileName);
2、通过实践,将Josnk 汉字转成UTF8格式,如:“中文汉字”,可以显示“中文汉字”。说明Post过程中,中文没有以UTF8格式传递。
(1)首先在JSON字符生成时,改成UTF8,也不行。
(2)HTTPEncode(Ansitoutf8(S)),Utf8Encode(s),HttpEncode(UTF8Encode(S)),UTF8Decode(HttpDecode(S2),偿试均失败。
(3)AddFormField('data', '中文汉字', 'utf-8'); 已指定utf-8格式,还是不行;
3、换个思路,Delphi发展到XE10,在汉字轮换上不可以需要我们如此大费功夫,应该能很好地实现的,是否格式上有问题。同时,定长自动加入“=”问题,肯定在传递的格式(网络传输的字节流)有问题,经查TIdFormDataField有个ContentTransfer属性。
IdMultipartFormData.pas单元文件中,ContentTransfer有三种类型:
const
sContentTransferPlaceHolder = 'Content-Transfer-Encoding: %s';
sContentTransferQuotedPrintable = 'quoted-printable';
sContentTransferBinary = 'binary';
Delphi默认ContentTransfer第二种:sContentTransferQuotedPrintable,就是'引用可打印'; 它是7位可打印的 ASCII编码方式。每个高位为1的码翻译为如=A1的16进制模式。
这种模式下,每76个字符用quoted-printable插入一次。这就是出现多余的=\\r\\n(“软”换行符)的原因。在支持quoted-printable服务器,都将在解码期间删除“软”换行符。
由于对方服务器不支持quoted-printable,所以解码后,加入了“=”等字符。
原因找到,那就换个模式吧。
换Binary类型试试:
paramStream.AddFormField('data',jsonstr,'UTF-8').ContentTransfer := sContentTransferBinary;
Post问题都解决。
4、分析:
(1)由于ContentTransfer默认sContentTransferQuotedPrintable,Post的'quoted-printable'格式,出现“=”字符。
(2)设置ContentTransfer为sContentTransferBinary后,它是数据流传输格式,实现UTF-8完整传输。(这里值得斟酌:它不编码的10进制数据流)
三、问题解决
procedure TMainFrm.Button5Click(Sender: TObject);
var paramStream: TIdMultiPartFormDataStream;
vResponse: TStringStream;
jsonstr: string;
MyList:TStringList;
begin
paramStream := TIdMultiPartFormDataStream.Create;
vResponse := TStringStream.Create('');
MyList:=TStringList.Create;
jsonstr:=GetJosnTxt; // 生成Json的自定义函数
// 定义http消息头
idhttp1.Request.ContentType := 'application/json';
//传递普通参数
paramStream.AddFormField('data',jsonstr,'UTF-8').ContentTransfer := sContentTransferBinary; // Binary格式传输
// 执行Post
IdHTTP1.Post('http://XXX.XXXX.com/api/v1/data', paramStream, vResponse); // 隐藏XXX
vres := vResponse.DataString; // Post返回值Utf8码
Memo1.Text := UnicodeToChinese(vres); // 显示反馈信息Utf8To
s:=FormatdateTime('yyyy-MM-dd HH:SS:mm',Now)+#13#10;
sTemp:=sTemp+S+Memo1.Text;
MyList:=TStringList.Create;
MyList.Text:=sTemp;
MyList.SaveToFile(sMainPath+'Upload.log'); // 保存Post信息
paramStream.Free;
vResponse.Free;
end;