通过winnet.dll异步访问http.get,记录坑点

winnet.dll访问http get post还是很方便的,为了增加超时设置,需要使用异步的方式来调用api,其中的坑点太多,以此文记录一下,方便以后查看。先上代码:

unit Unit2;

interface

uses
  Windows, WinInet, SyncObjs, SysUtils;

//全局函数,支持超时
function HttpGet(url: string; timeOut: Integer = MaxInt): string;

implementation

type
  TReqContext = class  //请求的上下文
  private
    m_eCall: TEvent;
    m_hOpen, m_hUrl: HINTERNET;
  public
    constructor Create;
    destructor Destroy; override;
  end;

{ TReqContext }

constructor TReqContext.Create;
begin
  m_eCall := TEvent.Create(nil, False, False, '');
end;

destructor TReqContext.Destroy;
begin
  if Assigned(m_hOpen) then
    InternetCloseHandle(m_hOpen);

  if Assigned(m_hUrl) then
    InternetCloseHandle(m_hUrl);

  m_eCall.Free;
  inherited;
end;


//回调函数
procedure Callback(hInternet: hInternet; //
  dwContext, dwInternetStatus: DWORD; //
  lpStatusInfo: HWND; dwStatusInfoLen: DWORD); stdcall;
var
  context: TReqContext;
  pret: PInternetAsyncResult;
begin
  context := TReqContext(dwContext);
  case dwInternetStatus of
    INTERNET_STATUS_HANDLE_CREATED: //创建openurl的句柄成功,绑定并触发事件
      begin
        pret := PInternetAsyncResult(lpStatusInfo);
        context.m_hUrl := Pointer(pret.dwResult);  //绑定句柄
      end;
    INTERNET_STATUS_REQUEST_COMPLETE: //openurl的请求完成
      context.m_eCall.SetEvent;
  end;
end;


//http get request
function HttpGet(url: string; timeOut: Integer = MaxInt): string;
var
  context: TReqContext;
  back1: INTERNET_STATUS_CALLBACK;
  buffer: array[0..50] of Char;
  interbuf: TInternetBuffersA;
  bret: Boolean;
begin
  timeOut := timeOut * 1000;
  context := TReqContext.Create;
  try
    context.m_hOpen := InternetOpen(PChar('http_get'), INTERNET_OPEN_TYPE_DIRECT, //
      nil, nil, INTERNET_FLAG_ASYNC); //这里一定要设置为:INTERNET_FLAG_ASYNC 表示异步请求

    //异步请求需要设置一个回调函数,这里用类的静态函数:callback
    back1 := InternetSetStatusCallback(context.m_hOpen, INTERNET_STATUS_CALLBACK(@Callback));
    if NativeInt(back1) = INTERNET_INVALID_STATUS_CALLBACK then
      Exit;

    //get方式请求url,这里注意最后一个参数,一定要大于0,如果为0根本收不到回调
    //一般来说最后一个参数是绑定的上下文,以便回调后访问相关参数
    context.m_hUrl := InternetOpenUrl(context.m_hOpen, PChar(url), nil, 0, INTERNET_FLAG_RELOAD, Integer(context));

    //接下来要检查openurl的返回句柄,一般来说都要异步返回
    if context.m_hUrl = nil then  //在异步函数中绑定
      if context.m_eCall.WaitFor(timeOut) <> wrSignaled then
        Exit;

    //有事件返回后,开始读数据
    //以下需要写成while循环,读到dwBufferLength=0时,表示读完
    //这里为了简单,只读了一次
    ZeroMemory(@buffer[0], SizeOf(buffer));
    ZeroMemory(@interbuf, SizeOf(interbuf));
    interbuf.dwStructSize := SizeOf(interbuf);
    interbuf.lpvBuffer := @buffer[0];
    interbuf.dwBufferLength := SizeOf(buffer) - 1;
    bret := InternetReadFileExA(context.m_hUrl, @interbuf, IRF_ASYNC, Integer(context));
    if bret then
    begin
      if interbuf.dwBufferLength > 0 then
        Result := StrPas(PChar(interbuf.lpvBuffer));
    end
    else
    begin
      //这里需要等待回调,然后再读
    end;
  finally
    context.Free;
  end;
end;

end.

调用方式:HttpGet("http://www.baidu.com", 5),返回为请求到的结果,这里为5秒超时。

发布了19 篇原创文章 · 获赞 10 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/ltk80/article/details/90271779