El problema
Muchas veces nos vemos en la necesidad de invocar un Web Service directamente desde la base de datos.
La utilización de Java dentro de la base de datos no siempre es una opción disponible, así que tuve que buscar una solución que sólo utilizara código PL/SQL.
La solución
Podemos utilizar el package UTL_HTTP para hacer los request SOAP directamente al servidor destino, esto si bien es más complicado que utilizar las clases proxy, nos evita tener que cargar Java en la base de datos.
La forma de invocar el package UTL_HTTP es la siguiente:
DECLARE req UTL_HTTP.req := NULL; resp UTL_HTTP.resp := NULL; respVal VARCHAR2(32000); reqXML VARCHAR2(32760); BEGIN /*Generamos un Request a la URL destino, el método debe ser POST */ req := UTL_HTTP.begin_request('http://servidor/ConsultaClientes', 'POST'); /*Creamos un mensaje SOAP tal cual se define en el WSDL*/ reqXML := '<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:m0="ConsultaClientes"> <SOAP-ENV:Body> <m:ConsultaClientes xmlns:m="http://servidor/ConsultaClientes"> <m0:mensaje> <m0:idcliente>C123452</m0:idcliente> </m0:mensaje> </m:ConsultaClientes> </SOAP-ENV:Body> </SOAP-ENV:Envelope>'; /*El contenido que enviamos es XML: */ UTL_HTTP.set_header(req, 'Content-Type', 'text/xml'); /*Establecemos el SOAPAction a invocar: */ UTL_HTTP.set_header(req, 'SOAPAction', '"rpc/http://servidor/ConsultaClientes"'); /*Indicamos en el header el tamańo del mensaje enviado: */ UTL_HTTP.set_header(req, 'Content-Length', LENGTH(xml)); /*Escribimos el body del request */ UTL_HTTP.write_text(req, xml); /*Obtenemos la respuesta */ resp := UTL_HTTP.get_response(req); /*Cargamos en la variable respVal la devolución del servidor */ UTL_HTTP.read_text(resp, respVal); /*Finalizamos la conexión HTTP */ UTL_HTTP.end_response(resp); EXCEPTION WHEN UTL_HTTP.end_of_body THEN UTL_HTTP.end_response(resp); END; /
Conclusion
De esta manera rápida pudimos invocar un Web Service remoto utilizando PL/SQL, a partir de allí es posible convertir lo recibido en la variable respVal a un XMLTYPE para un mejor manejo.
Espero que les haya servido!!
Gran código que me viene de perlas. Muchas gracias, voy a probarlo ahora mismo.
buenas, muy bueno el aporte. Yo necesito bajar un archivo (es un certificado de banco) con un webservice.. como podria hacer? gracias
Gracias por el aporte, este ejemplo funciona muy bien, sin embargo tengo que utilizarlo para consumir un web service donde los parametros (que son bastantes) vienen conformados en un documento xml con varios niveles de anidamiento, si mando un simple string con un valor me funciona pero si le envio el xml complejo el servidor me devuelve un “BAD REQUEST”(ya comprobe que el XML este bien formado). Probe hacer el consumo en visual basic y en menos de 15 minutos ya me estaba funcionando pero necesito hacerlo desde la base de datos. Alguna idea…
Hola, gracias por el codigo. Al generar el request al servidor destino aparece error ORA-12535 TNS:Operation timed out.
Debo hacer el consumo de un web service que, la estructura del xml tiene un nivel de complejidad mas alto que este ejemplo, por ejemplo tiene que ir un tipo de dato lista o tabla y de igual el xml que responde este web service es complejo y también trae un tipo de dato lista o tabla, como hago que se genere este xml que voy a enviar y como hago para luego recuperar, especialmente ese tipo de dato lista o tabla.
Gracias por su ayuda.
Hola gracias por la información publicada, ya he implementado el consumo desde BD de un WS pero al tratar de consumir con valores que tienen tildes me sale un error.
Gracias por tu ayuda,
Hola Sebas, tengo una pregunta ojala puedas ayudarme
Lo de invocar un ws funciona perfecto. Ahora estoy trabajando con servicios wcf a los cuales es posible configurar el binding o comportamiento entre aquellos que se conectan.
Entiendo que el cliente debe enviar su configuracion de binding el servicio para por ejemplo acordar con tiempo de respuesta, timeout, timeclosed, etc.
Es este binding que no sé donde configurarlo en la libreria utl_http. Deseo indicar al servicio que me espere por mas de 60 segudos porque me vota por timeout. Dentro del packege controlo esta excepcion pero quiero que no se produzca.
Eso..espero tus comentarios.
Roberto
Hola gusto de saludarte me podrias ayucar en consumir un servicio realizado en php, al seguir el ejemplo y sustituir por el que tengo me da el error del buffer porque lo que me devuelve es grandisimo, en espera de tu comentario muchas gracias
Mario, deberías usar un CLOB temporal e ir leyendo de a 32767 bytes. Por cada “readtext” haces un append al CLOB creado temporalmente.
Fijate que en esta página (en inglés) tenes una posible solución.
Saludos!!
Hola buena tarde gusto de saludarte, con un favor fijate que tengo un problema en el envio del mensaje el web service lo tengo en realizado en php, en espera te tu comentario muchas gracias
Mario, cual es el problema que tenés al enviar el mensaje en PHP?
Saludos!!