目录
RAD Studio 10.4.1关于Rest应用中字符串的编码解码及delphi处理html乱码问题
RAD Studio 10.4.1关于Rest应用中字符串的编码解码及delphi处理html乱码问题
一、与www相关的编码与解码方法
1.1、System.NetEncoding.pas
1.1.1、TNetEncoding.Base64格式
常被用于图片二进制码字符串(字节流)的编解码等:
应用1:将图片写入到数据库通用字段类型Blob,拿到图片的16进制字符串,前面再加上X,才可以Insert或Update为Blob字段类型;TBlobField(ABlob:TField).SaveToStream(AMemoryStream);
应用2:图片在互联网上Json传输后的Rest转化:
TBytes = TArray<Byte>; //:可以强制转化一下:array of Byte
Input :=
TBytesStream.LoadFromFile(FileName).Bytes;
//或用TBytesStream的子类TStringStream,TBytesStream的父类为内存流TMemoryStream:
Input :=
TStringStream.LoadFromFile(FileName).Bytes;
Output1 :=
TNetEncoding.Base64.Encode(Input: array of Byte): string; //Base64编码
Output2 :=
TNetEncoding.Base64.Decode(Output1 ): string; //Base64解码
Output_FileBytes :=
TNetEncoding.Base64.DecodeStringToBytes(Output2 ): TBytes; //Base64解码
TStringStream.Create(Output_FileBytes);
TStringStream.SaveToFile(Output_File: string);
//若使用TStringStream,不要再多此一举地:
Input :=
TStringStream.LoadFromFile(FileName).DataString;
Output1 :=
TNetEncoding.Base64.Decode(Input): string; //Base64编码
//因为还涉及到只读属性TStringStream.Encoding: TEncoding问题;很多同学经常这样使用,否则你还得去判断字串符的TEncoding编码格式
//若使用TStringStream,不要再多此一举地:
Input :=
TStringStream.LoadFromFile(FileName).DataString;
Output1 :=
TNetEncoding.Base64.Decode(Input): string; //Base64编码
//因为还涉及到只读属性TStringStream.Encoding: TEncoding问题;很多同学经常这样使用,否则你还得去判断字串符的TEncoding编码格式
1.1.2、TNetEncoding.HTML格式
常被用于对HTML文档代码的编解码等:
TNetEncoding.HTML.Encode(const Input: string): string; //HTML编码
TNetEncoding.HTML.Decode(const Input: string): string; //HTML解码
1.1.3、TNetEncoding.URL格式
常被用于对URL代码的编解码等:
TNetEncoding.URL.Encode(const Input: string): string; //URL编码:URL: TURLEncoding;
TNetEncoding.URL.Decode(const Input: string): string; //URL解码:URL: TURLEncoding;
function URLDecode(const AValue: string): string; inline;
//:解码URL编码的字符串:内联
function EncodeAuth(const Auth: string; const AExtraUnsafeChars: TUnsafeChars = []): string; inline;
//:编码验证:内联
function EncodeQuery(const AQuery: string; const AExtraUnsafeChars: TUnsafeChars = []): string; inline;
//:编码Get查询参数:内联
function EncodeForm(const AInput: string; const AExtraUnsafeChars: TUnsafeChars = []; AEncoding: TEncoding = nil): string; inline;
//:编码表单:内联
function FormDecode(const AValue: string; AEncoding: TEncoding = nil): string; inline;
//:解码表单:内联
function EncodePath(const APath: string; const AExtraUnsafeChars: TUnsafeChars = []): string;
//:编码路径
function Encode(const AInput: string; const ASet: TUnsafeChars; const AOptions: TEncodeOptions; AEncoding: TEncoding = nil): string; overload;
//:URL编码
function Decode(const AValue: string; const AOptions: TDecodeOptions; AEncoding: TEncoding = nil): string; overload;
//:解码URL编码的字符串
不安全的字符有哪些:
TURLEncoding = class(TNetEncoding)
public
type
//:不安全的字符:
//UnsafeChar = 32..127;
UnsafeChar = Byte;
TUnsafeChars = set of UnsafeChar;
TEncodeOption = (SpacesAsPlus, EncodePercent);
TEncodeOptions = set of TEncodeOption;
TDecodeOption = (PlusAsSpaces);
TDecodeOptions = set of TDecodeOption;
不安全的字符的序数:
const FormUnsafeChars: TUnsafeChars = [Ord('"'), Ord(''''), Ord(':'), Ord(';'), Ord('<'), Ord('='), Ord('>'),
Ord('@'), Ord('['), Ord(']'), Ord('^'), Ord('`'), Ord('{'), Ord('}'), Ord('|'), Ord('/'), Ord('\'), Ord('?'), Ord('#'),
Ord('&'), Ord('!'), Ord('$'), Ord('('), Ord(')'), Ord(','), Ord('~')];
const AuthUnsafeChars: TUnsafeChars = [Ord('"'), Ord(''''), Ord(':'), Ord(';'), Ord('<'), Ord('='), Ord('>'),
Ord('@'), Ord('['), Ord(']'), Ord('^'), Ord('`'), Ord('{'), Ord('}'), Ord('|'), Ord('/'), Ord('\'), Ord('?'), Ord('#')];
const PathUnsafeChars: TUnsafeChars = [Ord('"'), Ord('<'), Ord('>'), Ord('^'), Ord('`'), Ord('{'), Ord('}'), Ord('|'),
Ord('/'), Ord('\'), Ord('?'), Ord('#'), Ord('+')];
const QueryUnsafeChars: TUnsafeChars = [Ord('"'), Ord(''''), Ord('<'), Ord('>'), Ord('#')];
URL编码注意事项(以下抄录自“高勇三层Rest服务器产品”):
URL编码规则:
签名验证时,要求对字符串中除了“-”、“_”、“.”之外的所有非字母数字字符都要:
替换成百分号(%)后跟两位大写的十六进制数:十六进制数中字母必须为大写。
注意事项:
1. 某些系统方法,例如.NET系统方法HttpUtility.UrlEncode会将‘=’编码成‘%3d’,
而不是将:‘=’编码成%3D,导致加密签名通不过验证,请开发者注意检查。
2.Java 1.3和早期版本中,调用java.net.URLEncoder下的方法进行URL编码时,
某些特殊字符并不会被编码,例如星号(*)。
由于URL编码规则中规定了星号(*)必须编码,因此在请求字符串中含星号(*)的情况下,
如果使用了上述方法,会导致生成的签名不能通过验证。
因此,如果参数值中含有* ,在使用类java.net.URLEncoder下的方法进行编码后,
需开发人员手动将星号字符:“*”替换为“%2A”,否则将导致加密签名一直通不过验证,请开发者注意检查。
3. 某些语言的urlencode方法会把“空格”编码为“+”,实际上应该编码为“%20”。
这也将生成错误的签名,导致签名通不过验证。
请开发者注意检查,手动将“+”替换为“%20”。
在PHP中,推荐用rawurlencode方法进行URL编码。
1.1.4、关于TNetEncoding其它可用的转化函数
//关于TNetEncoding其它可用的转化函数:
TNetEncoding = class
public
function Decode(const Input, Output: TStream): Integer; overload;
function Decode(const Input: array of Byte): TBytes; overload;
function Decode(const Input: string): string; overload;
function Encode(const Input, Output: TStream): Integer; overload;
function Encode(const Input: array of Byte): TBytes; overload;
function Encode(const Input: string): string; overload;
function DecodeStringToBytes(const Input: string): TBytes;
function EncodeBytesToString(const Input: array of Byte): string; overload;
function EncodeBytesToString(const Input: Pointer; Size: Integer): string; overload;
class property Base64: TNetEncoding read GetBase64Encoding;
class property HTML: TNetEncoding read GetHTMLEncoding;
class property URL: TURLEncoding read GetURLEncoding;
end;
1.2、Web.HTTPApp.pas
function HTTPDecode(const AStr: string): string; inline; deprecated 'Use TNetEncoding.URL.Decode';
function HTTPEncode(const AStr: string): string; inline; deprecated 'Use TNetEncoding.URL.Encode';
function HTMLEncode(const AStr: string): string; inline; deprecated 'Use TNetEncoding.HTML.Encode';
function HTMLDecode(const AStr: string): string; inline; deprecated 'Use TNetEncoding.HTML.Decode';
Delphi 10.3后过时了:分别推荐使用上述1.1.3、TNetEncoding.URL格式和1.1.2、TNetEncoding.HTML格式。
1.3、IdStrings.pas
源码在$(Delphi)\source\Indy10\Protocols下
{对表示预定义字符的字符进行编码和解码
HTML4的实体。}
{处理&<>“字符}
function StrHtmlEncode (const AStr: String): String;
function StrHtmlDecode (const AStr: String): String;
{处理&<>"'字符}
function StrXHtmlEncode(const ASource: String): String;
function StrXHtmlDecode(const ASource: String): String;
1.4、关于网页html乱码
//uses System.pas;
{ //:关于字符串的定义:
_RawByteStr = RawByteString;
{$IFDEF NEXTGEN}
UTF8String = type _AnsiString(65001);
RawByteString = type _AnsiString($ffff); //:$ffff= 65535
{$NODEFINE UTF8String}
{$NODEFINE RawByteString}
{$ELSEIF Defined(LINUX64) or Defined(OSX64) or Defined(ANDROID)}
UTF8String = type AnsiString(65001);
RawByteString = type AnsiString($ffff); //:$ffff= 65535
{$NODEFINE UTF8String}
{$NODEFINE RawByteString}
{$ELSE}
UTF8String = type AnsiString(65001);
RawByteString = type AnsiString($ffff); //:$ffff= 65535
{$ENDIF}
PUTF8String = ^UTF8String;
PRawByteString = ^RawByteString;
{$IF Defined(NEXTGEN) or Defined(LINUX64) or Defined(OSX64) or Defined(ANDROID)}
{$NODEFINE PUTF8String}
{$NODEFINE PRawByteString}
{$ENDIF NEXTGEN or LINUX64 or OSX64 or ANDROID}
function UTF8ToWideString(const S: _RawByteStr): _WideStr; inline;
function UTF8ToString(const S: _RawByteStr): string; inline; overload;
}
//网页Html的代码用这个函数转化一下,就不乱码啦:
function HtmlDecode(AHtml: string):string;
begin
{$IFDEF UNICODE}
Result:= AHtml;
{$ELSE}
Result:= UTF8ToString(AHtml);
{$ENDIF}
end;
//网页Html的代码用这个函数转化一下,就不乱码啦:
function HtmlDecode(AHtml: string):string;
begin
{$IFDEF UNICODE}
Result:= AHtml;
{$ELSE}
Result:= UTF8ToString(AHtml);
{$ENDIF}
end;
二、进制转化
2.1、16进制string转10进制整数int
function HexStrToInt(AHexStr :string):Integer;
begin
Result:= StrToInt('$'+UpperCase(LHexStr));
end;
2.2、10进制整数int转16进制string
function IntToHexStr(AInt :Integer):string;
var
LInt: Integer;
LHexStr: string;
begin
Result:= Format( '%.2x' ,[AInt] );
end;
2.3、16进制和2进制互转
//uses system.class.pas;
procedure BinToHex(const Buffer: TBytes; BufOffset: Integer;
var Text: TBytes; TextOffset: Integer; Count: Integer); overload;
function HexToBin(const Text: PChar; TextOffset: Integer;
var Buffer: TBytes; BufOffset: Integer; Count: Integer): Integer; overload;
用法函数:
//16进制字符串转2进制字符串
function HexStrToBinStr(AHexStr: string):string;
var
LResult : WideString;
begin
SetLength(LResult , Length(AHexStr) div 4);
HexToBin(PWideChar(AHexStr), LResult [1], Length(AHexStr) div SizeOf(Char));
Result:= LResult ;
end;
//2进制字符串转16进制字符串
function BinStrToHexStr(ABinStr: string):string;
var
LResult : String;
begin
SetLength(LResult , Length(ABinStr) * 4);
BinToHex(ABinStr[1], PWideChar(LResult), Length(ABinStr) * SizeOf(Char));
Result:= LResult ;
end;