【问题标题】:How do I parse a web URL?如何解析网页 URL?
【发布时间】:2013-05-22 23:13:17
【问题描述】:

我需要能够将 URL 分解为不同的段。以这条路径为例:

http://login:password@somehost.somedomain.com:8080/some_path/something_else.html?param1=val&param2=val#nose
\__/   \___/ \______/ \_____________________/ \__/\____________________________/ \___________________/ \__/
 |       |      |               |               |                |                        |              |
Scheme Username Password       Host            Port             Path                    Query         Fragment

这应该分解如下:

Protocol: HTTP
Username: login
Password: password
Host: somehost.somedomain.com
Port: 8080
Path Info: /some_path/something_else.html
Query String: param1=val&param2=val

如何在 Delphi 中做到这一点?有什么现成的东西可以为我分解吗?如果没有,我该如何解析所有不同的可能格式?这是假设它甚至可能是不同的协议,例如 HTTPS 或 RTSP。

【问题讨论】:

  • 我希望密码不是明文。
  • @eggy 从技术上讲是这样,这就是某些系统的身份验证方式。是否需要对其进行加密取决于服务器实现。
  • @eggy 补充一下,我注意到的此类 Web 服务器实际上是硬件 API,例如交换机/路由器、IP 监控摄像头、VOIP 电话等。

标签: delphi parsing url delphi-xe2


【解决方案1】:

XE2 随 Indy 一起提供,为此目的有一个 TIdURI 类,例如:

uses
  ..., IdURI;

var
  URI: TIdURI;

URI := TIdURI.Create('http://login:password@somehost.somedomain.com:8080/some_path/something_else.html?param1=val&param2=val');
try
  // Protocol = URI.Protocol
  // Username = URI.Username
  // Password = URI.Password
  // Host = URI.Host
  // Port = URI.Port
  // Path = URI.Path
  // Query = URI.Params
finally
  URI.Free;
end;

【讨论】:

  • +1 更好的是,当某些东西已经用一种语言封装和实现时,它几乎总是一个优势:)
  • Indy 不是 Delphi 语言的一部分。它只是一个预先捆绑的第三方库。但至少 URI 解析没有外部依赖,因为它是用纯 Delphi 代码实现的。
  • 我的意思是在 IDE 中可用。 Indy 当然不是 Delphi 的一部分,这就是它是 Indy 的原因 :) 无论如何,为了便于使用,我可能最终还是会使用这个解决方案。
  • 等等,所以如果这个 Indy 方法不依赖任何东西并且自己解析它,那么我认为这可能是合适的解决方案。改为接受这个,因为它在技术上只需要 Indy 的存在,几乎所有版本的 Delphi 都附带了它。
【解决方案2】:

您可以使用InternetCrackUrl 方法。

试试这个简单的

{$APPTYPE CONSOLE}

uses
  Windows,
  SysUtils,
  WinInet;

procedure ParseURL(const lpszUrl: string);
var
  lpszScheme      : array[0..INTERNET_MAX_SCHEME_LENGTH - 1] of Char;
  lpszHostName    : array[0..INTERNET_MAX_HOST_NAME_LENGTH - 1] of Char;
  lpszUserName    : array[0..INTERNET_MAX_USER_NAME_LENGTH - 1] of Char;
  lpszPassword    : array[0..INTERNET_MAX_PASSWORD_LENGTH - 1] of Char;
  lpszUrlPath     : array[0..INTERNET_MAX_PATH_LENGTH - 1] of Char;
  lpszExtraInfo   : array[0..1024 - 1] of Char;
  lpUrlComponents : TURLComponents;
begin
  ZeroMemory(@lpszScheme, SizeOf(lpszScheme));
  ZeroMemory(@lpszHostName, SizeOf(lpszHostName));
  ZeroMemory(@lpszUserName, SizeOf(lpszUserName));
  ZeroMemory(@lpszPassword, SizeOf(lpszPassword));
  ZeroMemory(@lpszUrlPath, SizeOf(lpszUrlPath));
  ZeroMemory(@lpszExtraInfo, SizeOf(lpszExtraInfo));
  ZeroMemory(@lpUrlComponents, SizeOf(TURLComponents));

  lpUrlComponents.dwStructSize      := SizeOf(TURLComponents);
  lpUrlComponents.lpszScheme        := lpszScheme;
  lpUrlComponents.dwSchemeLength    := SizeOf(lpszScheme);
  lpUrlComponents.lpszHostName      := lpszHostName;
  lpUrlComponents.dwHostNameLength  := SizeOf(lpszHostName);
  lpUrlComponents.lpszUserName      := lpszUserName;
  lpUrlComponents.dwUserNameLength  := SizeOf(lpszUserName);
  lpUrlComponents.lpszPassword      := lpszPassword;
  lpUrlComponents.dwPasswordLength  := SizeOf(lpszPassword);
  lpUrlComponents.lpszUrlPath       := lpszUrlPath;
  lpUrlComponents.dwUrlPathLength   := SizeOf(lpszUrlPath);
  lpUrlComponents.lpszExtraInfo     := lpszExtraInfo;
  lpUrlComponents.dwExtraInfoLength := SizeOf(lpszExtraInfo);

  InternetCrackUrl(PChar(lpszUrl), Length(lpszUrl), ICU_DECODE or ICU_ESCAPE, lpUrlComponents);

  Writeln(Format('Protocol : %s',[lpszScheme]));
  Writeln(Format('Host     : %s',[lpszHostName]));
  Writeln(Format('User     : %s',[lpszUserName]));
  Writeln(Format('Password : %s',[lpszPassword]));
  Writeln(Format('Path     : %s',[lpszUrlPath]));
  Writeln(Format('ExtraInfo: %s',[lpszExtraInfo]));
end;

begin
  try
   ParseURL('http://login:password@somehost.somedomain.com/some_path/something_else.html?param1=val&param2=val');
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  readln;
end.

这将返回

Protocol : http
Host     : somehost.somedomain.com
User     : login
Password : password
Path     : /some_path/something_else.html
ExtraInfo: ?param1=val&param2=val

【讨论】:

  • +1 太棒了,我在几分钟前编辑了我的问题并将端口号添加到示例中。
  • @JerryDodge:此解决方案具有依赖项:Windows 2000+ 和 WinInet。
  • @RemyLebeau 改写:太多的库依赖 :) 不讨厌 Indy 但我猜这就是 Indy 在幕后使用的东西(我总是更喜欢低级的做事方式,虽然我并不总是理解它是如何工作的,这成为使用预制库的优势)
  • TIdURI 不使用任何外部 API 进行解析。
  • OT:出于好奇,InternetCrackUrl 无法处理方案组件中的冒号(例如,一个真实的示例jdbc:jtds:sqlserver://localhost/cabinet)由于某种原因(调用成功,但返回的组件错误)。这当然不涉及 HTTP 方案,但值得知道 WinInet 在这种情况下失败了(Indy 正确处理了这种情况)。 [已投票]
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-09-20
  • 1970-01-01
  • 2014-08-23
  • 2016-04-11
  • 2015-09-17
  • 1970-01-01
相关资源
最近更新 更多