Pregunta

Estoy tratando de hacer solicitudes HTTP desde Delphi usando las funciones de WinInet.

Hasta ahora tengo:

function request:string;
var
  hNet,hURL,hRequest: HINTERNET;
begin
  hNet := InternetOpen(PChar('User Agent'),INTERNET_OPEN_TYPE_PRECONFIG or INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
  if Assigned(hNet) then 
  begin
  try
    hURL := InternetConnect(hNet,PChar('http://example.com'),INTERNET_DEFAULT_HTTP_PORT,nil,nil,INTERNET_SERVICE_HTTP,0,DWORD(0));
    if(hURL<>nil) then
      hRequest := HttpOpenRequest(hURL, 'POST', PChar('param=value'),'HTTP/1.0',PChar(''), nil, INTERNET_FLAG_RELOAD or INTERNET_FLAG_PRAGMA_NOCACHE,0);
    if(hRequest<>nil) then
      HttpSendRequest(hRequest, nil, 0, nil, 0);
    InternetCloseHandle(hNet);
  except
    on E : Exception do
      ShowMessage(E.ClassName+' error raised, with message : '+E.Message);
  end;
  end
end;

Pero esto no hace nada (estoy olfateando el tráfico http de la red para ver si funciona). He utilizado con éxito InternetOpenURL pero también necesito enviar una solicitud POST y esa función no lo hace.

¿Podría alguien mostrarme un ejemplo simple? El resultado que quiero es obtener la página de respuesta http en una var como cadena.

¿Fue útil?

Solución

Tengo toda la parte de url / nombre de archivo desordenada con el código anterior. Estoy usando este de Jeff DeVore ahora y funciona bien:

function request(const AUrl, AData: AnsiString; blnSSL: Boolean = True): AnsiString;
var
  aBuffer     : Array[0..4096] of Char;
  Header      : TStringStream;
  BufStream   : TMemoryStream;
  sMethod     : AnsiString;
  BytesRead   : Cardinal;
  pSession    : HINTERNET;
  pConnection : HINTERNET;
  pRequest    : HINTERNET;
  parsedURL   : TStringArray;
  port        : Integer;
  flags       : DWord;
begin
  ParsedUrl := ParseUrl(AUrl);

  Result := '';

  pSession := InternetOpen(nil, INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);

  if Assigned(pSession) then
  try
    if blnSSL then
      Port := INTERNET_DEFAULT_HTTPS_PORT
    else
      Port := INTERNET_DEFAULT_HTTP_PORT;
    pConnection := InternetConnect(pSession, PChar(ParsedUrl[0]), port, nil, nil, INTERNET_SERVICE_HTTP, 0, 0);

    if Assigned(pConnection) then
    try
      if (AData = '') then
        sMethod := 'GET'
      else
        sMethod := 'POST';

      if blnSSL then
        flags := INTERNET_FLAG_SECURE or INTERNET_FLAG_KEEP_CONNECTION
      else
        flags := INTERNET_SERVICE_HTTP;

      pRequest := HTTPOpenRequest(pConnection, PChar(sMethod), PChar(ParsedUrl[1]), nil, nil, nil, flags, 0);

      if Assigned(pRequest) then
      try
        Header := TStringStream.Create('');
        try
          with Header do
          begin
            WriteString('Host: ' + ParsedUrl[0] + sLineBreak);
            WriteString('User-Agent: Custom program 1.0'+SLineBreak);
            WriteString('Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'+SLineBreak);
            WriteString('Accept-Language: en-us,en;q=0.5' + SLineBreak);
            WriteString('Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7'+SLineBreak);
            WriteString('Keep-Alive: 300'+ SLineBreak);
            WriteString('Connection: keep-alive'+ SlineBreak+SLineBreak);
          end;

          HttpAddRequestHeaders(pRequest, PChar(Header.DataString), Length(Header.DataString), HTTP_ADDREQ_FLAG_ADD);

          if HTTPSendRequest(pRequest, nil, 0, Pointer(AData), Length(AData)) then
          begin
            BufStream := TMemoryStream.Create;
            try
              while InternetReadFile(pRequest, @aBuffer, SizeOf(aBuffer), BytesRead) do
              begin
                if (BytesRead = 0) then Break;
                BufStream.Write(aBuffer, BytesRead);
              end;

              aBuffer[0] := #0;
              BufStream.Write(aBuffer, 1);
              Result := PChar(BufStream.Memory);
            finally
              BufStream.Free;
            end;
          end;
        finally
          Header.Free;
        end;
      finally
        InternetCloseHandle(pRequest);
      end;
    finally
      InternetCloseHandle(pConnection);
    end;
  finally
    InternetCloseHandle(pSession);
  end;
end;

ParseUrl es una función que divide una URL en " nombre de host / nombre de archivo " y TStringArray es una matriz de cadenas. Todavía tengo que revisar el código mañana, pero se ve bien y en mi sniffer vi que se enviaban los datos de la publicación y los encabezados.

Otros consejos

Personalmente prefiero usar la synapse para todos mis TCP / IP trabajo. Por ejemplo, una publicación HTTP simple se puede codificar como:

uses
  httpsend;

function testpost;
begin
  stm := tStringstream.create('param=value');
  try
    HttpPostBinary('http://example.com',Stm);
  finally
    stm.free;
  end;
end;

La biblioteca está bien escrita y es muy fácil de modificar para satisfacer sus requisitos específicos. La última versión de Subversion funciona sin problemas para Delphi 2009 y Delphi 2010. Este marco no está basado en componentes, sino que es una serie de clases y procedimientos que funcionan bien en un entorno de subprocesos múltiples.

El tercer parámetro (lpszObjectName) para HttpOpenRequest debe ser la URL que desea solicitar. Es por eso que la documentación describe el quinto parámetro (lpszReferer) como " puntero a una cadena terminada en nulo que especifica la URL del documento del que se obtuvo la URL en la solicitud (lpszObjectName). & Quot;

Los datos publicados se envían con HttpSendRequest ; El parámetro lpOptional se describe así:

  

Puntero a un búfer que contiene datos opcionales que se enviarán inmediatamente después de los encabezados de solicitud. Este parámetro se usa generalmente para operaciones POST y PUT. Los datos opcionales pueden ser el recurso o la información que se publica en el servidor. Este parámetro puede ser NULL si no hay datos opcionales para enviar.

El segundo parámetro para InternetOpen debería ser solo el nombre del servidor ; No debe incluir el protocolo. El protocolo que especifique con el sexto parámetro.

Después de enviar la solicitud, puede leer la respuesta con < code> InternetReadFile y InternetQueryDataAvailable .

No solo verifique si las funciones API devuelven cero y luego continúe en la siguiente línea. Si fallan, llame a GetLastError para averiguar por qué. El código que ha publicado no generará excepciones, por lo que es inútil atrapar alguno. (Y de todos modos es una tontería "manejarlos" de la forma en que lo hace. No se dé cuenta de una excepción que aún no sabe cómo solucionar. Deje que todo lo demás llegue a la persona que llama, o la persona que llama, etc.)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top