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!!
Es posible implementar este codigo sin estar conectado a la base de datos?, debido a que debo usarlo cuando realice un login failure, es decir, el usuario esté bloqueado, o la cuenta expirada, etc… por lo tanto no habrá coneccion a la base de datos…
muchas gracias!
Hi! There are certainly a lot of details like that to take into consideration. That is a great point to bring up. I offer the thoughts above as general inspiration but clearly there are questions like the one you bring up where the most important thing will be working in honest good faith. I don?t know if best practices have emerged around things like that, but I am sure that your job is clearly identified as a fair game. Both boys and girls feel the impact of just a moment’s pleasure, for the rest of their lives.
CREATE OR REPLACE
FUNCTION SWEJEMPLO RETURN VARCHAR2 AS
BEGIN
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://(ip)/su/wsvad/wsad.asmx', ‘POST’);
/*Creamos un mensaje SOAP tal cual se define en el WSDL*/
reqXML := ‘
string
string
‘;
/*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’, ‘”http://www.um.edu.co/isVad”‘);
/*Indicamos en el header el tamańo del mensaje enviado: */
UTL_HTTP.set_header(req, ‘Content-Length’, LENGTH(reqXML));
/*Escribimos el body del request */
UTL_HTTP.write_text(req, reqXML);
/*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);
return respVal;
EXCEPTION
WHEN UTL_HTTP.end_of_body THEN
UTL_HTTP.end_response(resp);
return ‘nada’;
END;
END SWEJEMPLO;
me sale este error ayuda
ORA-06502: PL/SQL: error : buffer de cadenas de caracteres demasiado pequeño numérico o de valor
ORA-06512: en línea 5
Process exited.
hola queria saber si hay algun codigo ejemplo para invocar un web service desde un pl sql en oracle 8i, Gracias!!!
Estaba probando el código y tengo un problema, imprimo el http_resp.status_code y me envía el status 401 que significa UNAUTHORIZED,
¿alguien sabe como solucionar este problema?
que permisos requiere?… xq el servicio que trato de consumir esta abierto para todo el mundo… es del banco, que te envia el tipo de cambio del dolar.
aqui esta la especificacion del servicio:
http://www.banguat.gob.gt/variables/ws/TipoCambio.asmx?op=TipoCambioDia
cualquier ayuda se agradece… :D
Tengo un problema cuando invoco al web service y este se tarda en responder me gustaria saber si hay alguna manera de saber si llegó la peticicion (el request) o lo tiene en espera procesando otros.
Necesito algo para evaluar si debo o no, volver a enviar la petición.
Me ha sido de mucha utilidad esta información. Tengo ahora el siguiente problema, el WS a consumir tiene certificado de seguridad (es un https) y me da los siguientes errores al levantar la línea del UTL_HTTP.begin_request:
ORA-29273: fallo en la solicitud HTTP
ORA-29024: Fallo de validación de certificado
ORA-06512: en linea 3
Gracias y saludos
Mil disculpas solo quiero saber si me pueden dar una mano con este problema
SOAP-ENV:Client
No Deserializer found to deserialize a 'GetFullName:m0:mensaje' using encoding style 'null'. [java.lang.IllegalArgumentException]
/WsSample2-WsSample2-context-root/MyWebService1
He seguido el ejemplo y obtengo el siguiente error. Yo obtengo el siguiente error:
ORA-12541: TNS:no listener
ORA-06512: at line 11
29273. 00000 – “HTTP request failed”
cual podría ser el problema, la verdad cualquier tipo de ayuda me viene muy útil.
saludos
señores me a salido el siguiente error. si alguien pude y quiere ayudar se lo agradesco
[1]: (Error): ORA-06550: line 33, column 56: PLS-00201: identifier ‘XML’ must be declared ORA-06550: line 33, column 4: PL/SQL: Statement ignored ORA-06550: line 35, column 30: PLS-00201: identifier ‘XML’ must be declared ORA-06550: line 35, column 4: PL/SQL: Statement ignored
Milfar, fijate que hay un error en la linea:
UTL_HTTP.set_header(req, ‘Content-Length’, LENGTH(xml));
Debería ser:
UTL_HTTP.set_header(req, ‘Content-Length’, LENGTH(reqXML));
Y en vez de:
UTL_HTTP.write_text(req, xml);
Debería ser:
UTL_HTTP.write_text(req, reqXML);
Espero que ese sea tu error, de paso aprovecho y corrijo el post así queda el código corregido.
Saludos!!
Tengo un problema al ejecutar el consumo de un WS me devuelve el error siguiente
999Referencia a objeto no establecida como instancia de un objeto.
Cual consideran puede ser el problema ???
Kramirez, cual es el código de error ORA?
Saludos!!
Hola, dejo esto por si alguien puede ayudarme.
Tengo un caso donde invoco un WS desde el browser y me responde esto:
‘
00Exitosa3900000046419535899999100.00DOP’
y cuando invoco el WS desde mi pl/sql entonces me retorna esto:
‘
<?xml version=”1.0″ encoding=”utf-8″?><DetalleReciboPago version=”1.00″><CodigoMensaje>00</CodigoMensaje><DescripcionMensaje>Exitosa</DescripcionMensaje><NumeroReferencia>39</NumeroReferencia><NumeroAutorizacion>000000032499675</NumeroAutorizacion><IDTransaccionBanco>99999</IDTransaccionBanco><ValorPagado>100.00</ValorPagado><Moneda>DOP</Moneda></DetalleReciboPago>’
Puede alguien decirme a que se debe esto?
Saludos.
Todo esto ya lo hemos vivido y solucionado. El problema que tenemos ahora es que al intentar usar un WS en una url segura (https) necesitamos establecer los certificados de acceso mediante el OWM pero esta herramienta no nos permite realizar ninguna acción (se abre e intenta crear, abrir, etc. ….y se queda pegado).
Cualquier comentario se agradece !
ORA-12545
buen dia ejecute el procedimiento pero me genera el siguiente error.
ORA-29273: HTTP request failed
ORA-06512: at “SYS.UTL_HTTP”, line 1029
ORA-12545: Connect failed because target host or object does not exist
ORA-06512: at line 13
@Kamilo, aparentemente no tenés acceso a ese host destino que intentas invocar.
El servidor destino lo ponés en la siguiente linea:
Donde “servidor” debería ser el nombre de tu server destino, y “/ConsultaClientes” la dirección final donde se aloje el Web Service de destino.
Si eso lo tenés bien configurado, entonces debería probar si el servidor dónde se aloja la base de datos tiene conectividad con el servidor destino.
Saludos!!
Volviendo al bonito ejemplo
He desarrollado un Servicio Web(WS) en Visual Studio 2005, y tengo la base de datos en Oracle 10g Express, para pruebas…
Mi WS se llama http://localhost/ews_ora/
Que posee como 10 metodos
y el metodo que seo invocar es… http://localhost/ews_ora/Service.asmx?op=Peticion_XML
Peticion_XML recibe 3 argumento tipo String y devuelve solo 1 tipo String siempre.
segun el ejemplo de esta pagina tendria que poner mis 3 argumento en: reqXML
@Juliusmanx, a ver si entiendo la idea, ¿vos querés invocar desde la base de datos ese Web Service?
Entonces para utilizar este ejemplo, deberías como primer medida obtener el XML de ejemplo necesario para invocar ese WS.
Una vez que tenés ese XML de request, lo que debés hacer es completarlo con los parámetros que precises.
Saludos!!
@Faustino, para escribir un “xml” en los comentarios podés probar con poner:
< tag >valor< tag >
Los espacios permiten que el comentario pase sin ser analizado como HTML.
Saludos!!
@Sebas, Hola Sebas, aqui te envio el mensaje xml que necesito parsear y poner el calor de los campos en variables tipo Varchar2.
00
Consulta realizada con exito. Edenorte Dominicana.
0060000000
Erika Zabaleta
Cristian test 15 4
Tester 01
100000000000
20080423
000800000006
DOP
5000.0
DG
CLIENTE NUEVO
20080423
000800000006
DOP
5000.0
DG
CLIENTE NUEVO
Si te fijas tengo primero 6 campos, y el ultimo que es tiene un sub xml, que tiene unas estructuras que hay que capturar esos calores tambien en variables Varchar2
Hola Sebas.
Como puedo convertir la variable respVal en un XMLType?
@Faustino, Lo tenés que hacer de la siguiente manera:
resp := UTL_HTTP.get_response(req);
UTL_HTTP.read_text(resp, val);
UTL_HTTP.end_response(resp);
val_xml := xmltype(val);
Es decir, utilizando la función xmltype. Una vez que lo tengas ahí dentro podés usar val_xml.extract para sacar los datos.
Espero te sirva!
@Juan, gracias por la ayuda.
Mi variable xmltype esta declarada v_resp xmltype; y la cariable donde captura la respuesta del web service es respVal varchar2(32000);
cuando agrego la linea v_resp := xmltype(respVal); y luego le doy a compilar mi stored procedure, el pl de freeza y no me responde.
@Faustino, a lo mejor tenés un problema con el formato de la respuesta y no la está pudiendo transformar a xmltype, probá hacer:
SELECT xmltype(‘todo el código xml’) FROM DUAL;
y fijate qué sucede.
@Juan, Perfecto Juan, me di cuenta que tenia campos del xml mal nombrados. Al parecer esto generaba algún conflicto. Ya me compilo bien.
Por ultimo y espero no molestarte más hermano, ya tengo mi variable xmltype llena…. como puedo esos campos de esa estructura xml que tengo ahi, parecearlos para asignar esos valores a diferentes variables de salida de mi procedure?
Gracias anticipadas.
@Faustino,
Para eso te sugiero que investigues un poco de XPath, que es lenguaje utilizado para parsear archivos XML. Si querés fijate en este link:
http://download.oracle.com/docs/cd/B10501_01/appdev.920/a96616/arxml24.htm
Un ejemplo sería, si tenés un XML con la siguiente estructura:
Para sacar el valor podrías utilizar:
ó
Si tuvieras atributos se agrega un @ adelante, por ejemplo:
Suerte!
@Juan, Definitivamente eres un conocedor de este tema. Yo por mi parte es primera vez que trabajo con XML en mi corta vida de programador. jejeje. no tengo como agradecerte. el getStringVal() me a funsionado bien.
El unico inconveniente es que por ejemplo cuando uso esta linea
V_RESPONSE_CODE_OUT := v_resp.extract(‘//codigoRespuesta’).getStringVal();
la variable V_RESPONSE_CODE_OUT me la llena con 00, a mi me interesa que solo la llene con el 00 que es el valor del campo en la estructura xml.
¿es eso posible?
@Faustino, entiendo que lo que querés es el valor de un atributo y no del tag… si es así ponele un @ adelante:
v_resp.extract(’//@codigoRespuesta’).getStringVal();
Sino investigate ese link que te pasé para encontrar alguna forma de parsearlo y que te sirva.
@Faustino, ¿podrías incluir una parte del XML que tienes que parsear?
De paso, pasanos la declaración de “V_RESPONSE_CODE_OUT” así podemos ver el tipo de dato que estas utilizando.
Si vos tenés más de un tag llamado “codigoRespuesta” y utilizás el XPath en modo búsqueda, podés estar devolviendo el array de la respuesta, por ejemplo:
En ese XML estarías encontrando más de una respuesta para “//codigoRespuesta”.
Saludos!
@Sebas, hola.
En este caso no sucedera porque me responde un xml con tres campos unicos. y las variables en que quiero almanecar el contenido de esos campos son declaradas Varchar2, tal es el caso de V_RESPONSE_CODE_OUT.
para este xml:
00
Consulta exitosa
quiero almacenar solo el calor 00 en V_RESPONSE_CODE_OUT, sindo esta una variable varchar2. Hasta ahora estoy logrando almacenar en la V_RESPONDE_CODE_OUT toda la linea, es decir, 00. pero solo quiero que sea 00.
Gracias de antemano
@Faustino, probaste con el @ que te dije? Seguramente es un atributo. Sino adjuntamos todo el código xml para que podamos verlo.
Saludos,
Juan
seria posible que me pasen un correo donde les pueda mandar todo el xml que estoy recibiendo, y como quiero capturar cada valor de los campos del xml en variables tipo varchar2.
mi correo es faustino_a80@hotmail.com
Esto porque no se como escribir el xml aqui sin que salga incompleto.
@jic, Juan, como estas?
Te he escrito correos respondiendo el mensaje que me enviaras y no he recibido respuestas. Nada, solo queria saber si aun estas en la disposicion de ayudarme. Saludos hermano, y en definitiva gracias por toda la ayuda que me has brindado hasta ahora.
Juan, que error te manda? podrías explicar un poco mas como estas armando la variable XML?
Saludos!!
Help !!!..
Tengo mi archivo WSDL.. ahora quiero publicarlo desde un PL/SQL,
Quiero echar andar este ejemplo… me manda un error en la linea sig:
UTL_HTTP.set_header(req, ‘Content-Length’, LENGTH(xml));
como lo hago funcionar para poder replicar lo mismo en mi caso.
Saludos
Estimados,
Estuve en el mismo problema hace poco, y me parece una buena solucion,
Pero si estan con oracle 10 (creo que desde el 9 en realidad)
hay un Pk mas util, el UTL_DBWS, es mas sencillo para los webservices,
y el problema mas comun es solo setear el proxy, te mando una pag con la referencia, fuera de ello todo me fue de maravilla!
Espero les sirva!
http://www.oracle-base.com/articles/10g/utl_dbws10g.php
y para setear el proxy, es casi igual que en el utl_http
Marco, no me llegó en el comentario tu XML de prueba, pero cual es el error que obtienes?
Si queres más ayuda te escribo un mail al que dejaste registrado en tu comentario.
Saludos!
Estimado Sebas, realmente el problema en si a mi entender no es la invocacion, sino mas bien la generación del XML de la variable reqXML. Como indique anteriormente, el WSDL que me genera mi aplicacion de .NET es bastante distinto al del ejemplo por lo que pienso que quizas lo estoy armando de manera errónea.
El WSDL de mi aplicacion es el siguiente:
Por lo que no se exactamente que es lo que debo tomar para generar la cadena correcta del XML. Adicionalmente, se me ocurrió probar con el texto SOAP que se especifica dentro de la pagina de prueba del Webservice cuyo texto transcribo pero tampoco me funciono con este…
int
Que puedo hacer???
Marco, para armar el request te sugiero que copies el xml de request que arma algún programa que permita invocar Web Services, como por ejemplo XML Spy, una vez que tengas el request armado lo asignas a la variable reqXML.
La página que tengas que invocar para el Web Service la pones en la linea:
req := UTL_HTTP.begin_request(‘http://servidor/ConsultaClientes', ‘POST’);
Cambiando ‘http://servidor/ConsultaClientes' por la página destino que corresponda.
Espero que te sirva,
Saludos!
Saludos, una consulta, tengo un problema al utilizar el snippet de codigo debido a que el WSDL que me genera mi webservice es muy distinto del suyo, no se si se deba a que mi WebService esta hecho en .NET, ademas dentro de su codigo no veo que ebn ningun lado se especifique la pagina ASMX para consumir el WerService, no es esto necesario?
Una consulta adicional, el Web Service puede estar publicado en un servidor distinto a donde se encuentra la llamada del PL/SQL?
Pingback: DbRunas - Invocar Web Services desde PL/SQL en Oracle