delphi XE7 HttpEncode 编码问题

近期在做网址编码相关的工作,发现在用 XE5 编译的时候,一切正常,拿 到 XE7下 就 结果错误了。百度了下,谷歌 了下,有人提出,但是,我没有找到答案,也许都没有碰到这个问题,也许都己经自己默默的解决了,在此 小记一下,方便后人,也方便自己 查寻。

例子 : 原字符   "过年"

httpencode(‘过年‘) 结果 :

XE5为  %B9%FD%C4%EA

XE7 调用 相当函数结果 %E8%BF%87%E5%B9%B4

百思不得其解啊,折腾了很长时间,后来终于想到是不是 此函数 官方更新修改了,(没办法,人比较笨)

于是查看源码:

XE5的 web.httpapp 中(分string 和 ansistring, 我用ansistring 版本得到 期望的结果):

  1 function HTTPEncode(const AStr: string): string;
  2 // The NoConversion set contains characters as specificed in RFC 1738 and
  3 // should not be modified unless the standard changes.
  4 const
  5   NoConversion = [Ord(‘A‘)..Ord(‘Z‘), Ord(‘a‘)..Ord(‘z‘), Ord(‘*‘), Ord(‘@‘),
  6                   Ord(‘.‘), Ord(‘_‘), Ord(‘-‘), Ord(‘0‘)..Ord(‘9‘), Ord(‘$‘),
  7                   Ord(‘!‘), Ord(‘‘‘‘), Ord(‘(‘), Ord(‘)‘)];
  8 var
  9   Sp, Rp: PChar;
 10 begin
 11   SetLength(Result, Length(AStr) * 3);
 12   Sp := PChar(AStr);
 13   Rp := PChar(Result);
 14   while Sp^ <> #0 do
 15   begin
 16     if Ord(Sp^) in NoConversion then
 17       Rp^ := Sp^
 18     else
 19       if Sp^ = ‘ ‘ then
 20         Rp^ := ‘+‘
 21       else
 22       begin
 23         FormatBuf(Rp, 3, string(‘%%%.2x‘), 6, [Ord(Sp^)]);
 24         Inc(Rp,2);
 25       end;
 26     Inc(Rp);
 27     Inc(Sp);
 28   end;
 29   SetLength(Result, Rp - PChar(Result));
 30 end;
 31
 32 function HTTPDecode(const AStr: string): string;
 33 var
 34   Sp, Rp, Cp: PChar;
 35   S: string;
 36 begin
 37   SetLength(Result, Length(AStr));
 38   Sp := PChar(AStr);
 39   Rp := PChar(Result);
 40   Cp := Sp;
 41   try
 42     while Sp^ <> #0 do
 43     begin
 44       case Sp^ of
 45         ‘+‘: Rp^ := ‘ ‘;
 46         ‘%‘: begin
 47                // Look for an escaped % (%%) or %<hex> encoded character
 48                Inc(Sp);
 49                if Sp^ = ‘%‘ then
 50                  Rp^ := ‘%‘
 51                else
 52                begin
 53                  Cp := Sp;
 54                  Inc(Sp);
 55                  if (Cp^ <> #0) and (Sp^ <> #0) then
 56                  begin
 57                    S := Char(‘$‘) + Cp^ + Sp^;
 58                    Rp^ := Char(StrToInt(string(S)));
 59                  end
 60                  else
 61                    raise EWebBrokerException.CreateFmt(sErrorDecodingURLText, [Cp - PChar(AStr)]);
 62                end;
 63              end;
 64       else
 65         Rp^ := Sp^;
 66       end;
 67       Inc(Rp);
 68       Inc(Sp);
 69     end;
 70   except
 71     on E:EConvertError do
 72       raise EConvertError.CreateFmt(sInvalidURLEncodedChar,
 73         [Char(‘%‘) + Cp^ + Sp^, Cp - PChar(AStr)])
 74   end;
 75   SetLength(Result, Rp - PChar(Result));
 76 end;
 77
 78 function HTTPEncode(const AStr: AnsiString): AnsiString;
 79 // The NoConversion set contains characters as specificed in RFC 1738 and
 80 // should not be modified unless the standard changes.
 81 const
 82   NoConversion = [‘A‘..‘Z‘,‘a‘..‘z‘,‘*‘,‘@‘,‘.‘,‘_‘,‘-‘,
 83                   ‘0‘..‘9‘,‘$‘,‘!‘,‘‘‘‘,‘(‘,‘)‘];
 84 var
 85   Sp, Rp: PAnsiChar;
 86 begin
 87   SetLength(Result, Length(AStr) * 3);
 88   Sp := PAnsiChar(AStr);
 89   Rp := PAnsiChar(Result);
 90   while Sp^ <> #0 do
 91   begin
 92     if Sp^ in NoConversion then
 93       Rp^ := Sp^
 94     else
 95       if Sp^ = ‘ ‘ then
 96         Rp^ := ‘+‘
 97       else
 98       begin
 99         System.AnsiStrings.FormatBuf(Rp^, 3, AnsiString(‘%%%.2x‘), 6, [Ord(Sp^)]);
100         Inc(Rp,2);
101       end;
102     Inc(Rp);
103     Inc(Sp);
104   end;
105   SetLength(Result, Rp - PAnsiChar(Result));
106 end;

在XE7中

web.httpapp:

function HTTPEncode(const AStr: string): string;
begin
  Result := TNetEncoding.URL.Encode(AStr);
end;

查看 system.netencoding

找到

function TNetEncoding.DoEncode(const Input: array of Byte): TBytes;
begin
  Result := TEncoding.UTF8.GetBytes(DoEncode(TEncoding.UTF8.GetString(@Input[0])));
end;
查看类定义:  TURLEncoding = class(TNetEncoding)
  protected
    function DoDecode(const Input: string): string; overload; override;
    function DoEncode(const Input: string): string; overload; override;
  end;

查看函数代码:

function TURLEncoding.DoEncode(const Input: string): string;
// The NoConversion set contains characters as specificed in RFC 1738 and
// should not be modified unless the standard changes.
const
  NoConversion = [Ord(‘A‘)..Ord(‘Z‘), Ord(‘a‘)..Ord(‘z‘), Ord(‘*‘), Ord(‘@‘),
                  Ord(‘.‘), Ord(‘_‘), Ord(‘-‘), Ord(‘0‘)..Ord(‘9‘), Ord(‘$‘),
                  Ord(‘!‘), Ord(‘‘‘‘), Ord(‘(‘), Ord(‘)‘)];

  procedure AppendByte(B: Byte; var Buffer: PChar);
  const
    Hex = ‘0123456789ABCDEF‘;
  begin
    Buffer[0] := ‘%‘;
    Buffer[1] := Hex[B shr 4 + Low(string)];
    Buffer[2] := Hex[B and $F + Low(string)];
    Inc(Buffer, 3);
  end;

var
  Sp, Rp: PChar;
  MultibyteChar: TBytes;
  I, ByteCount: Integer;
begin
  // Characters that require more than 1 byte are translated as "percent-encoded byte"
  // which will be encoded with 3 chars per byte -> %XX
  // Example: ?character
  //   Multibyte representation: C391 (2 bytes)
  //   URL encode representation: %C3%91
  //
  // So the worst case is 4 bytes(max) per Char, and 3 characters to represent each byte
  SetLength(Result, Length(Input) * 4 * 3);
  Sp := PChar(Input);
  Rp := PChar(Result);
  SetLength(MultibyteChar, 4);
  while Sp^ <> #0 do
  begin
    if Ord(Sp^) in NoConversion then
    begin
      Rp^ := Sp^;
      Inc(Rp)
    end
    else if Sp^ = ‘ ‘ then
    begin
      Rp^ := ‘+‘;
      Inc(Rp)
    end
    else
    begin
      if (Ord(Sp^) < 128) then
        // Single byte char
        AppendByte(Ord(Sp^), Rp)
      else
      begin
        // Multi byte char
        ByteCount := TEncoding.UTF8.GetBytes([Sp^], 0, 1, MultibyteChar, 0);
        for I := 0 to ByteCount - 1 do
          AppendByte(MultibyteChar[I], Rp);
      end
    end;
    Inc(Sp);
  end;
  SetLength(Result, Rp - PChar(Result));
end;

似乎有点不同。

目前是我自己建立一个函数 ,复制XE5版本的 代码 放在XE7里面调用,得到希望的结果的。

代码:

function MyHTTPEncode(const AStr: AnsiString): AnsiString;
// The NoConversion set contains characters as specificed in RFC 1738 and
// should not be modified unless the standard changes.
const
  NoConversion = [‘A‘..‘Z‘,‘a‘..‘z‘,‘*‘,‘@‘,‘.‘,‘_‘,‘-‘,
                  ‘0‘..‘9‘,‘$‘,‘!‘,‘‘‘‘,‘(‘,‘)‘];
var
  Sp, Rp: PAnsiChar;
begin
  SetLength(Result, Length(AStr) * 3);
  Sp := PAnsiChar(AStr);
  Rp := PAnsiChar(Result);
  while Sp^ <> #0 do
  begin
    if Sp^ in NoConversion then
      Rp^ := Sp^
    else
      if Sp^ = ‘ ‘ then
        Rp^ := ‘+‘
      else
      begin
        System.AnsiStrings.FormatBuf(Rp^, 3, AnsiString(‘%%%.2x‘), 6, [Ord(Sp^)]);
        Inc(Rp,2);
      end;
    Inc(Rp);
    Inc(Sp);
  end;
  SetLength(Result, Rp - PAnsiChar(Result));
end;

时间: 2024-08-08 04:04:21

delphi XE7 HttpEncode 编码问题的相关文章

SynEdit(Delphi XE7)的安装和基本使用

一.花絮 delphi自带的memo显示sql语句看的太累人了,今天决定美化一下.最起码要有“语法着色”.“显示行号”这2个功能. 意外发现了 SynEdit 控件. SynEdit是一个免费的文字编辑器,支持37种程序语言语法高亮度显示,可以一次编辑多个文件 SynEdit 支持语法高亮.word-wrap.代码自动完成.模版组件.导出到 html 等格式的功能. SynEdit 是一个纯 VCL/CLX 控件,无须任何其他运行库支持,著名的 HeidiSQL 数据库管理工具就是使用该控件开发

Delphi XE7 安装

delphi xe7是一款跨平台的应用程序开发工具,它能快速开发Windows.Mac.iOS.Android和各种电子产品的平台的应用程序, 新版xe7使用了Microsoft Windows图形用户界面的许多先进特性和设计思想,采用了弹性可重复利用的完整的面向对象程序语言(Object-Oriented Language),通过全新的控件和样式使您的Windows应用变得现代化,具有简单.高效.功能强大的特点. 在移动端方面,delphi xe7提供mobile apps的连结功能,可以支援

Delphi XE7中新并行库

Delphi XE7中增加了新的并行库,和.NET的Task和Parellel相似度99%. 具体内容可以看下面的文章: http://www.delphifeeds.com/go/s/119574 如果你熟悉.NET,这个功能并没有大的新意,可对Delphi程序员来说却非常实用.之前要实现多线程,唯一的办法是使用TThread类,而且过程十分繁琐.新的并行库彻底简化了这个过程. 估计下一步就该实现Async和Await异步执行结构了 另外最近Delphi的排名竟然有所上升并且进了前十,对还在用

试用Delphi XE7制作Iphone6抢购工具

暑期没地方去,闲着无聊,看到Delphi XE7已出,又加上最近香港Iphone6抢购的火热,而我之前也有关注过Iphone6的抢购,故趁此闲暇时光,做个抢购工具给需要的朋友用一下. 程序的流程,主要是借用了Swish大侠的qworker,HTTPS主要是用了Idhttp去实现,数据的保存使用了JSON 程序下载 http://download.csdn.net/detail/cntlis/8002561 具体的预约代码如下,里边代码不算精炼,主要考虑循环次数有限 procedure DoSta

DELPHI XE7 新的并行库

DELPHI XE7 的新功能列表里面增加了并行库System.Threading, System.SyncObjs. 为什么要增加新的并行库? 还是为了跨平台.以前要并行编程只能从TThread类继承进行多线程处理,大家知道TThread类是从WINDOWS的线程API封装起来的,它封装的是WINDOWS的多线程的东西,是不能脱离WINDOWS的,当然是不能跨平台的.DELPHI现在走的是原生跨平台的道路,一切DELPHI的基础类库都要从只支持WINDOWS改为支持多平台,这是一个庞大而缓慢的

Free Lua Scripting Interpreter Library For Delphi XE7 Firemonkey On Android And IOS

http://www.fmxexpress.com/free-lua-scripting-interpreter-library-for-delphi-xe7-firemonkey-on-android-and-ios/ http://blog.spreendigital.de/tag/delphi/ http://blog.spreendigital.de/2015/02/18/verysimple-lua-2-0-a-cross-platform-lua-5-3-0-wrapper-for-

Delphi XE7的安卓程序如何调用JAVA的JAR,使用JAVA的类?

本文使用工具和全部源码下载: http://download.csdn.net/detail/sunylat/8190765 为什么我们要在Delphi XE7的安卓程序调用Java的JAR,使用JAVA的类?如果能够这样做,那么就意味着我们把Delphi开发的安卓程序扩展到了一个更大的开发范围了,理论上可以调用任意JAVA编写的代码,对于同时精通Delphi和JAVA的程序员来说,简直如虎添翼!! 我差不多用了一天时间吧,最终在老猫的帮助下,成功实现了在Delphi XE7的安卓程序中调用JA

Delphi XE7中使用JSON

Delphi XE7有一个对JSON处理的单元,在你需要使用JSON的单元里面引入"System.json",随后你就可以用Delphi自己的json处理类了.我写的小例子只是对包含字符串和数组的JSON进行解析,这两种数据类型,我觉得是实际使用中最常用.有用的类型,所以我仅仅用这两种例子做演示! 演示代码: { 功能:DelphiXE7中使用JSON -------------------------------------------------------------------

delphi XE7 中的消息

在delphi XE7的程序开发中,消息机制保证进程间的通信. 在程序中,消息来自: 1)系统: 通知你的程序用户输入,涂画以及其他的系统范围的事件: 2)你的程序:不同的程序部分之间的通信信息.   什么时候使用消息?       当你写程序的时候,通常是使用事件而不是消息,控件触发事件让你来处理而其内部则是通过消息机制处理的(对你是透明的),从而实现和其他控件之间的通信以及处理系统信息.       不管咋样,有时你确实需要使用消息. 你的程序必须响应一个系统或者框架没有定义的事件(或者没有