Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Internet (https://www.clubdelphi.com/foros/forumdisplay.php?f=3)
-   -   Dudas con IdHTTP de Indy 9 (https://www.clubdelphi.com/foros/showthread.php?t=89267)

vicvil 26-10-2015 20:10:07

Dudas con IdHTTP de Indy 9
 
Hola buenas, tengo que enviar un archivo xml a un webservices y estoy usando los componentes Indy.

Para ello utilizo el IdHHTP, pero aquí es donde tengo algunas dudas.

El ejemplo que hay a continuación es el archivo que debería recibir el webservices, lo que está marcado en rojo corresponde al Header. Y es aquí donde tengo las dudas y es ¿cómo puedo hacer para indicar lo de la primera línea? es decir, que en el encabezado aparezca "POST /cgi_dte/UPL/DTEUpload HTTP/1.0"

La línea que dice "Cookie" tengo que ingresar un token que me entrega el webservice a traves de otro proceso, ese token ya lo tengo, pero ¿cómo lo ingreso en el encabezado?

Y la última pregunta es sobre el Boundary=7d23e2a11301c4. ¿Qué es específicamente ese boundary? y ¿de donde se saca esos caractéres?

Código:

POST /cgi_dte/UPL/DTEUpload HTTP/1.0^M
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg,
application/vnd.ms-powerpoint, application/ms-excel,
application/msword, */*^M
Referer: {URL que referencia a upload Ej.
http://empresaabc.cl/test.html}^M
Accept-Language: es-cl^M
Content-Type: multipart/form-data: boundary={boundary data: Ej. ------
---------------------7d23e2a11301c4}^M
Accept-Encoding: gzip, deflate^M
User-Agent: Mozilla/4.0 (compatible; PROG 1.0; Windows NT 5.0; YComp
5.0.2.4)^M
Host: {Host Id. Ej: https://maullin.sii.cl}^M
Content-Length: {largo total de mensaje sin Req. Header. Ej.: 10240}^M
Connection: Keep-Alive^M
Cache-Control: no-cache^M
Cookie: TOKEN={Entregado por Autenticación. Ej.: YZD0II2ApZjlM}^M
^M[/color]
{Comienzo de Multipart/Form-data}
-----------------------------7d23e2a11301c4^M
Content-Disposition: form-data; name="rutSender"^M
^M
1^M
-----------------------------7d23e2a11301c4^M
Content-Disposition: form-data; name="dvSender"^M
^M
9^M
-----------------------------7d23e2a11301c4^M
Content-Disposition: form-data; name="rutCompany"^M
^M
3^M
-----------------------------7d23e2a11301c4^M
Content-Disposition: form-data; name="dvCompany"^M
^M
5^M
-----------------------------7d23e2a11301c4^M
Content-Disposition: form-data; name="archivo"; filename="EnvioEjemplo.xml"^M
Content-Type: text/xml^M
^M
<?xml version="1.0" encoding="ISO-8859-1"?>^M
<EnvioDTE xmlns="http://www.sii.cl/SiiDte" ^M
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ^M
 xsi:schemaLocation="http://www.sii.cl/SiiDte EnvioDTE.xsd" ^M
 version="1.0">^M
<SetDTE ID="SetDoc">^M
…………………………………………………………………………….
</EnvioDTE>^M
^M
-----------------------------7d23e2a11301c4--^M

Para hacer esto tengo el siguiente código, a ver si estoy bien encaminado...

Código Delphi [-]
procedure Enviaarchivo;
var F : TStringList;//TextFile;
    SSLHandler: TIdSSLIOHandlerSocket;
begin  
  F:= TStringList.Create;
  F.LoadFromFile('c:\archivo.xml');
  IdSSLOpenSSLHeaders.Load;
  IdHTTP1.Request.CustomHeaders.clear;
  idHTTP1.Request.Clear;
  IdHTTP1.Request.CustomHeaders.Add('POST /cgi_dte/UPL/DTEUpload HTTP/1.0');
  IdHTTP1.Request.Accept:= 'image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, 
 application/vnd.ms-powerpoint, application/ms-excel, application/msword, */*';
  IdHTTP1.Request.Referer:= 'www.empresa.cl';
  IdHTTP1.Request.AcceptLanguage:= 'es-cl';
  IdHTTP1.Request.ContentType:= 'multipart/form-data: boundary='+'---------------------------7d23e2a11301c4';
  IdHTTP1.Request.AcceptEncoding:= 'gzip, deflate';
  IdHTTP1.Request.UserAgent:= 'Mozilla/4.0 (compatible; PROG 1.0; Windows NT 5.0; YComp 5.0.2.4)';
  IdHTTP1.Request.Host:= 'https://maullin.sii.cl';
  IdHTTP1.Request.ContentLength:= F.Count;//10000;
  IdHTTP1.Request.Connection:= 'Keep_Alive';
  IdHTTP1.Request.CacheControl:= 'no-cache';
  memo1.Lines.Add('-----------------------------7d23e2a11301c4' + #10#13);
  memo1.Lines.Add('Content-Disposition: form_data; name="rutSender"' + #10#13);
  memo1.Lines.Add(#10#13);
  memo1.Lines.Add(copy(FrmEnvioDTE.RutDTE,1,length(FrmEnvioDTE.RutDTE) - 2) + #10#13);
  memo1.Lines.Add('-----------------------------7d23e2a11301c4' + #10#13);
  memo1.Lines.Add('Content-Disposition: form_data; name="dvSender"' + #10#13);
  memo1.Lines.Add(#10#13);
  memo1.Lines.Add(copy(FrmEnvioDTE.RutDTE,length(FrmEnvioDTE.RutDTE), 1) + #10#13);
  memo1.Lines.Add('-----------------------------7d23e2a11301c4' + #10#13);
  memo1.Lines.Add('Content-Disposition: form_data; name="rutCompany"' + #10#13);
  memo1.Lines.Add(#10#13);
  memo1.Lines.Add(copy(FrmEnvioDTE.RutEmp,1,length(FrmEnvioDTE.RutEmp) - 2) + #10#13);
  memo1.Lines.Add('-----------------------------7d23e2a11301c4' + #10#13);
  memo1.Lines.Add('Content-Disposition: form_data; name="dvCompany"' + #10#13);
  memo1.Lines.Add(#10#13);
  memo1.Lines.Add(copy(FrmEnvioDTE.RutEmp,length(FrmEnvioDTE.RutEmp), 1) + #10#13);
  memo1.Lines.Add('-----------------------------7d23e2a11301c4' + #10#13);
  memo1.Lines.Add('Content-Disposition: form_data; name="archivo"; filename="DTEFXXX.xml"' + #10#13);
  memo1.Lines.Add('Content-Type: text/xml' + #10#13);
  memo1.Lines.Add(#10#13);
  {AssignFile(F, 'c:\archivo.xml');
  Reset(F);}

  memo1.Lines.Add(F.Text);
  memo1.Lines.Add(#10#13);
  memo1.Lines.Add(#10#13);
  memo1.Lines.Add('-----------------------------7d23e2a11301c4--' + #10#13);
  F.Free;
  memo1.Lines.SaveToFile('c:\archivo.xml');
  F:= TStringList.Create;
  F.LoadFromFile('c:\archivo.xml');
  IdHTTP1.Post('https://maullin.sii.cl',F);
  IdSSLOpenSSLHeaders.UnLoad;
end;

Cualquier ayuda, me servirá de mucho ya que llevo días en esto viendo foros y ejemplos.

vicvil 27-10-2015 21:37:34

Bueno hice un pequeño cambio al final del código para obtener el error:

Código Delphi [-]
Stream := TStringStream.Create('');
  Params := TIdMultipartFormDataStream.Create;
  Params.AddFile('DTEUpload', 'c:\archivo.xml', '');
  try
    IdHTTP1.Post('https://maullin.sii.cl',Params, Stream);
  except
    on E: Exception do
    ShowMessage('Se encontró un problema al enviar el archivo:' + E.Message);
  end;
  ShowMessage(Stream.DataString);

al enviar el archivo me arroja el siguiente error:

"HTTP/1.1 400 Bad Request"

¿Será por el hecho que me falta el token? o ¿puede estar faltándome algo más?
Cualquier idea se agradecerá

Ñuño Martínez 28-10-2015 10:26:54

Nunca he usado el IdHTTP de Indy, pero sí Synapse, y también he enviado todo tipo de documentos con PHP. A ver si te puedo echar una mano:

Efectivamente, las cabeceras deben enviarse antes que el documento, supongo que Indy ya se encarga de eso mediante la propiedad CustomHeaders. De todas formas, revisa que estás definiéndolas correctamente, ya que si no puede haber problemas a la hora de interpretarlas.

Por otro lado, el archivo que construyes en el "memo" no es XML. Es decir, todo lo que pones en ese código tiene pinta de ser la cabecera TCP/IP, HTTP, o del protocolo que sea, pero no es XML.

Respecto a las huellas o cookies, ¿no tiene IdHTTP métodos para gestionarlos? Lo digo porque es más cómodo que andar trapicheando con las cabeceras.

Respecto al error 400 que recibes, ¿quién te lo muestra, el servidor o el cliente? ¿Estás seguro de que las URLs están bien construidas y que los servicios funcionan correctamente?

vicvil 28-10-2015 21:12:54

hola Ñuño, gracias por responder,
La verdad es que yo estoy recién empezando a usar el componente IdHTTP y la verdad que no es mucha o derechamente casi nula la ayuda que existe en cuanto usarlo como cliente, mas bien toda la ayuda que he visto es respecto a usarlo como servidor, así es que estoy a tumbos aprendiendo.
Lo que hago para ingresar los datos en la cabecera, es ingresar directamente en las propiedades del componente, los datos que allí aparecen, es decir por ejemplo:

IdHTTP1.Request.AcceptLanguage:= 'es-cl';
IdHTTP1.Request.ContentType:= 'multipart/form-data: boundary='+'---------------------------7d23e2a11301c4';
IdHTTP1.Request.AcceptEncoding:= 'gzip, deflate';

no ingreso todo a traves de la propiedad cumtomheaders (no sé si habrá que ingresar toda la cabecera por ahí o como lo estaba haciendo yo basta).
En cuanto a cookie, la verdad no he visto que este componente tenga por donde ingresarlo.
Y en cuanto al error, los servicios están constantemente abiertos y no sé si es el servidor o el cliente quien me lo arroja.

roman 28-10-2015 21:33:01

Hace mucho que no trasteo con las Indy pero viendo sus propiedades y métodos yo indagaría los siguientes:

Código Delphi [-]
function Post(AURL: string; const ASource: TIdMultiPartFormDataStream): string; overload;

Esta es la modalidad del método Post que te permite mandar datos con múltiples partes (el XML iría como una de esas partes)

La clase TIdMultiPartFormDataStream parece ser la que te permite adjuntar el XML con su método AddFile.

También, la propiedad CookieManager del IdHttp parece ser la que te permitirá enviar la cookie que requieres.

// Saludos

vicvil 29-10-2015 16:13:15

Muchas gracias Roman.
voy a probar y les cuento.

vicvil 30-10-2015 21:39:56

Ñuño, ¿tienes algún ejemplo de cómo hacer esto con Synapse?

Ñuño Martínez 02-11-2015 12:43:04

Cita:

Empezado por vicvil (Mensaje 498667)
Ñuño, ¿tienes algún ejemplo de cómo hacer esto con Synapse?

Normalmente dejo que sea el propio Synapse que se encargue del trabajo sucio, ya que él mismo incluye clases que implementan los protocolos más comunes (FTP, SMTP, POP3, HTTP...).

Intentaré describir tu caso (más o menos y de memoria):
Código Delphi [-]
  VAR
    ArchivoXML: TFileStream;
    ClienteHTTP: THTTPSend;
  BEGIN
    ClienteHTTP := THTTPSend.Create;
    TRY
      ClienteHTTP.Protocol := '1.1';
      ClienteHTTP.UserAgent := 'Synapse HTTP Client'; { Puedes poner lo que te plazca. }
      ClienteHTTP.KeepAlive := TRUE;
      ClienteHTTP.Cookies.Values['TOKEN'] := 'YZD0II2ApZjlM';
      ClienteHTTP.MimeType := 'application/ms-excel';
      IF NecesitaClave THEN
      BEGIN
        ClienteHTTP.Username := EditNombreUsuario.Text;
        ClienteHTTP.Password := EditClave.Text
      END;
      ArchivoXML := TFileStream.Create (RutaArchivoXML, fmOpenRead);
      TRY
        ClienteHTTP.Document.CopyFrom (ArchivoXML, ArchivoXML.Size)
      FINALLY
        FreeAndNil (ArchivoXml) { Sólo destruye si existe, si no, lo ignora y evita el error. }
      END;
      ClienteHTTP.HTTPMethod ('POST', EditURL.Text);
      Application.MessageBox (
        Format ('Resultado:'#10'[%d] %s ', [ClienteHTTP.ResultCode, ClienteHTTP.ResultString])
      )
    FINALLY
      ClienteHTTP.Free
    END
  END
Seguramente tengas que afinar alguna cosa, pero más o menos sería así. Dudo que tengas que usar la propiedad "Headers".

vicvil 02-11-2015 20:58:06

Gracias Ñuño por tu cooperación,
Estoy implementando tu ejemplo adaptándolo a mis necesidades, pero cuando envío el archivo recibo el código 500 en http.resultcode, esto me indica que "El servidor encontró una condición inesperada que le impidió cumplir con la solicitud".
Yo creo que debe ser porque faltan partes del encabezado que no he podido encontrar cómo ingresar, como "Accept:", "Referer:", "Accept-Languaje:", "Accept-Encoding:", etc.
Intenté ingresarlo de la siguiente forma:

Código Delphi [-]
HTTP.Headers.add( 'POST /cgi_dte/UPL/DTEUpload HTTP/1.0'+ CRLF +
                        'Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-powerpoint, applicatio/ms-excel, application/msword, */*' + CRLF +
                        'Referer:http://www.empresa.cl'+ CRLF +
                        'Accept-Languaje: es-cl' + CRLF +
                        'Content-Type: multipart/form-data: boundary=---------------------------' + Bound + CRLF +
                        'Accept-Encoding: gzip, deflate' + CRLF +
                        'Host:https://maullin.sii.cl/cgi_dte/UPL/DTEUpload'+ CRLF +
                        'Content-Length:' + IntToStr(F.Count) + CRLF +
                        'Cache_Control: no-cache' + CRLF );

pero me aparece un error de Access Violation.

Ñuño Martínez 03-11-2015 14:24:46

El error 500 lo envía el servidor, y el problema está en el servidor. Él debería decir qué falla (cuál es esa condición inesperada). Si el programa servidor no lo has hecho tú, pregunta a quien lo hizo.

Por otro lado, la mitad o más de lo que añades en la propiedad "Headers" debes definirlo en otras propiedades, para que la clase construya correctamente la cabecera. Ten en cuenta que "Headers" es un TStringList, yo no añadiría los saltos de línea sino que añadiría cada línea por separado.

vicvil 05-11-2015 16:43:19

Gracias ñuño por tu aporte

vicvil 05-11-2015 21:12:14

Bueno después de probar varias cosas, entre ellas lo de synapse que amablemente me enseño ñuño, me decidí por probar nuevamente con indy y con ambos me daba el mismo resultado de error "HTTP/1.1 500". Así que me metí a la página web de la institución a la que debo enviar el archivo y me pude dar cuenta que la dirección no era la misma que aparece en el documento el cual ellos mismos redactaron, así que cambié el host y ahí resultó y ahora me envía el mensaje "HTTP/1.1 200 OK".
El problema que tengo ahora es que el stream que viene de vuelta viene encriptado y mi pregunta es ¿con que componente indy desencripto ese resultado?

Casimiro Notevi 06-11-2015 02:42:53

Cita:

Empezado por vicvil (Mensaje 498948)
El problema que tengo ahora es que el stream que viene de vuelta viene encriptado y mi pregunta es ¿con que componente indy desencripto ese resultado?

Crea un hilo nuevo con esa duda, y da detalles porque no somos adivinos ;)


La franja horaria es GMT +2. Ahora son las 21:52:12.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi