La función que se muestra a continuación es una implementación ligera de acceso a recursos HTTP que sirve tanto para peticiones GET como POST. Esta función no da soporte a conexiones seguras HTTPS ni al envío de parámetros que requieran un tratamiento especial, como puede ser el envío de ficheros. Estas limitaciones nos permiten contar con una función relativamente pequeña que se puede incluir fácilmente en cualquier proyecto o script de prueba.
La función cuenta con 4 constantes, declaradas en las primeras líneas de código, para definir los siguientes aspectos:
- cons_max_retries: Número de reintentos que vamos a realizar en caso de error de conexión.
- cons_result_ok: Mensaje resultado en caso de éxito.
- cons_result_error: Mensaje resultado en caso de error.
- cons_result_sharp: Carácter separador para montar los mensajes de respuesta compuestos.
El código completo de la función http_param se muestra a continuación:
create function http_param(
p_url in varchar2,
p_method in varchar2,
p_param in varchar2,
p_html_result out varchar2
) return varchar2
is
cons_max_retries CONSTANT number := 3; -- Maximum retries number.
cons_result_ok CONSTANT varchar2(10) := 'OK';
cons_result_error CONSTANT varchar2(10) := 'ERROR';
cons_result_sharp CONSTANT varchar2(1) := '#';
req UTL_HTTP.REQ;
resp UTL_HTTP.RESP;
v_value varchar2(1024);
v_url varchar2(200);
v_param varchar2(500);
v_param_length number;
v_html_result varchar2(32767);
retry boolean;
num_retries number;
v_result varchar2(1024);
begin
-- Init variables
v_url := p_url;
v_param := p_param;
v_param_length := length(v_param);
if p_method = 'GET' then
v_url := v_url||'?'||v_param;
end if;
retry := true;
num_retries := 1;
-- Retry loop
while retry and num_retries <= cons_max_retries loop
v_result := cons_result_ok;
begin
req := UTL_HTTP.BEGIN_REQUEST (url=> v_url, method => p_method);
UTL_HTTP.SET_HEADER (r => req,
name => 'Content-Type',
value => 'application/x-www-form-urlencoded');
if p_method = 'POST' then
UTL_HTTP.SET_HEADER (r => req,
name => 'Content-Length',
value => v_param_length);
UTL_HTTP.WRITE_TEXT (r => req,
data => v_param);
end if;
resp := UTL_HTTP.GET_RESPONSE(req);
-- Communication errors
if resp.status_code != 200 then
dbms_output.put_line('Connection error:');
dbms_output.put_line(' Resp.status_code: '||resp.status_code);
dbms_output.put_line(' Resp.reason_phrase: '||resp.reason_phrase);
dbms_output.put_line(' Resp.http_version: '||resp.http_version);
dbms_output.put_line(' Resp.private_hndl: '||resp.private_hndl);
v_result := cons_result_error||cons_result_sharp||'Resp.status_code: '||resp.status_code||' - Resp.reason_phrase: '||resp.reason_phrase;
-- Valid response
else
-- Read response
begin
loop
UTL_HTTP.READ_LINE(resp, v_value, TRUE);
v_html_result := v_html_result || v_value;
end loop;
exception
when UTL_HTTP.END_OF_BODY then
UTL_HTTP.END_RESPONSE(resp);
when others then
v_result := cons_result_error||cons_result_sharp||'ERROR -> http_param: error READ_LINE - '||sqlerrm;
dbms_output.put_line( v_result );
end;
end if;
retry := false;
exception
when UTL_HTTP.TRANSFER_TIMEOUT then
v_result := cons_result_error||cons_result_sharp||'WARNING -> http_param: error UTL_HTTP.TRANSFER_TIMEOUT (retry '||num_retries||'/'||cons_max_retries||') - '||sqlerrm;
dbms_output.put_line( v_result );
retry := true;
num_retries := num_retries + 1;
when UTL_HTTP.HTTP_CLIENT_ERROR then
v_result := cons_result_error||cons_result_sharp||'WARNING -> http_param: error UTL_HTTP.HTTP_CLIENT_ERROR (retry '||num_retries||'/'||cons_max_retries||') - '||sqlerrm;
dbms_output.put_line( v_result );
retry := true;
num_retries := num_retries + 1;
when UTL_HTTP.HTTP_SERVER_ERROR then
v_result := cons_result_error||cons_result_sharp||'WARNING -> http_param: error UTL_HTTP.HTTP_SERVER_ERROR (retry '||num_retries||'/'||cons_max_retries||') - '||sqlerrm;
dbms_output.put_line( v_result );
retry := true;
num_retries := num_retries + 1;
when UTL_HTTP.REQUEST_FAILED then
v_result := cons_result_error||cons_result_sharp||'WARNING -> http_param: error UTL_HTTP.REQUEST_FAILED (retry '||num_retries||'/'||cons_max_retries||') - '||sqlerrm;
dbms_output.put_line( v_result );
retry := true;
num_retries := num_retries + 1;
when OTHERS then
v_result := cons_result_error||cons_result_sharp||'ERROR -> http_param - '||sqlerrm;
dbms_output.put_line( v_result );
retry := false;
num_retries := num_retries + 1;
end;
end loop;
-- Result
p_html_result := v_html_result;
return v_result;
exception
when others then
v_result := cons_result_error||cons_result_sharp||'ERROR -> http_param - '||sqlerrm;
dbms_output.put_line('Error others: '||v_result);
return v_result;
end http_param;
Para probar su funcionamiento podemos realizar una consulta al servicio de información meteorológica de Yahoo! En este caso para la ciudad de Madrid:
declare
v_html_result varchar2(32767);
v_result varchar2(2048);
begin
v_result := http_param(
p_url => 'http://weather.yahooapis.com/forecastrss',
p_method => 'GET',
p_param => 'w=12578024&u=c',
p_html_result => v_html_result
);
dbms_output.put_line('Result: '||v_result);
dbms_output.put_line('HTML result: ');
if length(v_html_result) > 255 then
for i in 0..ceil(length(v_html_result)/255) loop
dbms_output.put_line(substr(v_html_result, ((255*i) + 1), 255));
end loop;
else
dbms_output.put_line(v_html_result);
end if;
end;
El resultado esperado, en caso de que logremos conectar con el servicio de Yahoo! desde nuestra sesión de base de datos, sería algo similar a esto:
Result: OK
HTML result: ...<xml_with_weather_data>...
Oracle 11g
Hay que tener en cuenta que a partir de la versión 11g de Oracle existe un control de acceso para el uso de cualquier protocolo que permita abrir conexiones externas a la base de datos. Este control de acceso se encuentra regulado por listas de acceso o ACL. Si no hemos habilitado el acceso a las URLs necesarias dando de alta las reglas oportunas en las ACL obtendremos un error como el siguiente:
ERROR#WARNING -> http_param: error UTL_HTTP.REQUEST_FAILED (retry 1/3) -
ORA-29273: HTTP request failed
ORA-06512: at "SYS.UTL_HTTP", line 1130
ORA-24247: network access denied by access control list (ACL)
ERROR#WARNING -> http_param: error UTL_HTTP.REQUEST_FAILED (retry 2/3) -
ORA-29273: HTTP request failed
ORA-06512: at "SYS.UTL_HTTP", line 1130
ORA-24247: network access denied by access control list (ACL)
ERROR#WARNING -> http_param: error UTL_HTTP.REQUEST_FAILED (retry 3/3) -
ORA-29273: HTTP request failed
ORA-06512: at "SYS.UTL_HTTP", line 1130
ORA-24247: network access denied by access control list (ACL)
Result: ERROR#WARNING -> http_param: error UTL_HTTP.REQUEST_FAILED (retry 3/3) -
ORA-29273: HTTP request failed
ORA-06512: at "SYS.UTL_HTTP", line 1130
ORA-24247: network access denied by access control list (ACL)
HTML result:
En la entrada «Control de acceso a recursos de red – ACL management» se explica cómo crear la ACL necesaria para completar la prueba de conexión con Yahoo!.
Me gusta esto:
Me gusta Cargando...