首页 > 解决方案 > 原生 Delphi HTTPClient 是否支持 SNI?

问题描述

我们必须在我们的休息请求中包含 SNI (Server_Name_Indication),因为服务器将在不久的将来托管多个虚拟域。我们使用的是在运行时创建的标准 THTTPClient 组件。一旦我们使用新证书添加新域,我们就会收到异常“服务器证书无效或不存在”(翻译自德语错误文本)

是否有一个特殊的标头值可以像基本身份验证一样存档 SNI?

下面是我们代码的简化版本(无日志记录、无代理、假 URL)。很抱歉,我无法提供我们正在使用的真实 URL。

我们希望我们必须增加 GetRequest 方法,但没有找到任何示例或提示。

unit Unit1;

interface

uses
  Winapi.Windows, WinApi.WinHTTP, System.Classes,
  Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls,
  System.Net.HTTPClient;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Edit1: TEdit;
    procedure Button1Click(Sender: TObject);
  private
    function PostRequest(const cRequest, cBody: string): string;
  public
    { Public declarations }
  end;

type
  TMyRestClient = class(TObject)
  private
    fHTTPClient: THTTPClient;
    fSysUrl: string;
    fUserID: string;
    fPassWD: string;
    //...
    function GetRequest(const cMethod, cUrl: string): IHTTPRequest;
  public
    constructor Create(const cUrl: string);
    destructor Destroy; override;
    function Post(const cRequest, cBody: string): string;

    //...
    property SystemUrl: string read fSysUrl write fSysUrl;
    property Username: string read fUserID write fUserID;
    property Password: string read fPassWD write fPassWD ;
  end;

var
  Form1: TForm1;

implementation

uses
  System.SysUtils, System.Variants, System.NetEncoding;

{$R *.dfm}

constructor TMyRestClient.Create(const cUrl: string);
begin
  fHTTPClient := THTTPClient.Create;
  SystemUrl := cUrl;
end;

destructor TMyRestClient.Destroy;
begin
  FreeAndNil(fHTTPClient);
  inherited Destroy;
end;

function TMyRestClient.GetRequest(const cMethod, cUrl: string): IHTTPRequest;
begin
  Result := fHTTPClient.GetRequest(cMethod, cUrl);
  Result.AddHeader('content-type', 'appplication/json');
  if (Password <> '') then
    Result.AddHeader('Authorization', 'Basic ' + TNetEncoding.Base64.Encode(Username + ':' + Password));
end;

function TMyRestClient.Post(const cRequest, cBody: string): string;
var
  iRequest: IHTTPRequest;
  iResponse: IHTTPResponse;
  aBody: TStringStream;
begin
  iRequest := GetRequest('POST', Format('%s/%s', [SystemUrl, cRequest]));
  aBody := TStringStream.Create(UTF8String(cBody));
  try
    iRequest.SourceStream := aBody;
    iResponse := fHTTPClient.Execute(iRequest);
  finally
    aBody.DisposeOf;
  end;
  if (iResponse.StatusCode <> HTTP_STATUS_OK) then
    raise Exception.CreateFmt('Post: %s failed (Code %d) %', [cRequest, iResponse.StatusCode, iResponse.StatusText]);
  Result := iResponse.ContentAsString;
end;

function TForm1.PostRequest(const cRequest, cBody: string): string;
var
  xClient: TMyRestClient;
begin
  xClient := TMyRestClient.Create('www.myserver.com/demo');
  try
    // Basic authentification (not used)
    xClient.Username := '';
    xClient.Password := '';
    Result := xClient.Post(cRequest, cBody);
  finally
    xClient.DisposeOf
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Edit1.Text := PostRequest('retrieve/paramvalue', '{''PARAM'':''VERSION''}' );
end;

标签: httpdelphisni

解决方案


推荐阅读