UTL_HTTP
功能描述
使用UTL_HTTP包可通过SQL和过程语言调用超文本传输协议HTTP,允许通过HTTP访问internet上的数据。该内置包定义了一些数据类型和子程序。
注意事项
该功能仅在数据库兼容模式为Oracle时能够使用(即创建DB时DBCOMPATIBILITY='A'),在其他数据库兼容模式下不能使用该特性。
使用该内置包的功能需要提前创建plpython3u插件,步骤参考python3环境配置。
数据类型
UTL_HTTP包中声明了几种RECORD类型,用于表示请求、响应。
REQ类型
功能描述
REQ类型用于接受HTTP的request请求。
语法格式
TYPE REQ RECORD(
url VARCHAR2(32767),
method VARCHAR2(64),
http_version VARCHAR2(64),
);
参数说明
url:http请求的URL,在BEGIN_REQUEST进行设置。
method:请求url的方法,在BEGIN_REQUEST创建请求之后设置。
http_version:发送请求的HTTP协议版本。
RESP类型
功能描述
RESP类型用于表示HTTP的响应。
语法格式
TYPE UTL_HTTP.RESP AS(
status_code PLS_INTEGER,
reason_phrase VARCHAR2(256),
http_version VARCHAR2(64),
buffer_id PLS_INTEGER);
参数说明
- status_code:Web服务器返回的状态代码。
- reason_phrase:Web服务器返回的描述状态代码的短文本消息。
- http_version:响应中使用的HTTP协议版本。
- buffer_id:RESP使用的缓冲区id。
子程序
表1 UTL_HTTP包支持的函数
函数 | 描述 |
---|---|
SET_TRANSFER_TIMEOUT | 设置UTL_HTTP从WEB服务器或代理服务器读取HTTP响应的超时值。 |
REQUEST | 从指定的URL请求检索数据。可直接用于SQL查询。 |
BEGIN_REQUEST | 开始一个新的HTTP请求。 |
SET_HEADER | 用于设置HTTP请求头。 |
GET_RESPONSE | 用于读取HTTP响应。 |
SET_BODY_CHATSET | Content-Type标头中未指定字符集时,设置请求体的字符集。 |
WRITE_TEXT | 在HTTP请求体中写入一些文本数据。 |
READ_LINE | 以文本形式读取HTTP响应正文,直到到达尾行。 |
READ_TEXT | 根据请求url返回内容的字符集编码信息,解码并读取指定个数的字符存入指定的缓冲区中。 如果不指定字符数,则默认读取32767个字符。 |
END_RESPONSE | 结束HTTP响应,完成HTTP请求和响应。 |
END_REQUEST | 结束HTTP请求。 |
GET_DETAILED_SQLERRM | 检索最后引发的异常的详细SQLERRM。 |
SET_TRANSFER_TIMEOUT
语法格式
UTL_HTTP.SET_TRANSFER_TIMEOUT(timeout);
参数说明
timeout:网络传输超时值(以秒为单位)。
REQUEST
语法格式
UTL_HTTP.REQUEST(url);
参数说明
url:请求的url地址。
BEGIN_REQUEST
语法格式
UTL_HTTP.BEGIN_REQUEST(r);
参数说明
r:http请求的URL。
SET_HEADER
语法格式
UTL_HTTP.SET_HEADER(r,name,value);
参数说明
- r:http请求。
- name:http的header名称。
- value:http的header值。
GET_RESPONSE
语法格式
UTL_HTTP.GET_RESPONSE(r);
参数说明
r:http响应。
SET_BODY_CHATSET
语法格式
UTL_HTTP.SET_BODY_CHATSET(r,charset);
参数说明
r:http响应。
charset:正文的字符集。
WRITE_TEXT
语法格式
UTL_HTTP.WRITE_TEXT(r,date);
参数说明
- r:http请求。
- date:需要在HTTP请求body正文中发送的文本数据。
READ_LINE
语法格式
UTL_HTTP.READ_LINE(r,date,crlf);
参数说明
- r:http响应。
- date:http的body文本。
- crlf:是否删除换行符。
READ_TEXT
语法格式
UTL_HTTP.READ_TEXT(
r IN OUT NOCOPY resp,
data OUT NOCOPY VARCHAR2 CHARACTER SET ANY_CS,
len IN PLS_INTEGER DEFAULT NULL);
参数说明
- r:HTTP的响应信息。
- data:缓冲区。
- len:需要读取的长度,默认值为NULL。
提示信息:
- 如果到达HTTP响应正文的末尾,则会引发“end of_body”异常。
- 如果发生读取超时,返回成功读取的所有数据;如果读取超时且未成功读取任何数据,引发“transfer_timeout”异常。
- 如果响应体使用多字节编码,在响应体末尾发现不完整的多字节编码字符,停止读取并返回已成功读取的内容;如果没有成功读取完整字符,引发“partial_multibyte_char”异常;如果发生了读取超时,导致已接收内容的末尾尚不能被解码,引发“transfer_timeout”异常。
- 根据响应报文的Context-Type获取字符集。如果未获取到字符集或不支持该字符集,引发“unsupported character set”异常。
- 如果传入len小于0,引发“bad argument”异常。
END_RESPONSE
语法格式
UTL_HTTP.END_RESPONSE(r);
参数说明
r:http响应。
END_REQUEST
语法格式
UTL_HTTP.END_REQUEST(r);
参数说明
r:http请求。
GET_DETAILED_SQLERRM
语法格式
UTL_HTTP.GET_DETAILED_SQLERRM
RETURN VARCHAR2;
示例
前置条件:
1、系统已经安装Python3环境。Linux操作系统可以使用如下命令查看Python3版本:
python3 -V
2、使用vsql工具连接至客户端。
vsql -p 5432 -d vastbase -r
3、安装plpython3u扩展。
create extension plpython3u;
4、创建并切换至兼容模式为Oracle的数据库db_oracle下。
CREATE DATABASE db_oracle dbcompatibility='A';
\c db_oracle
5、设置serveroutput为on(允许将dbms_output.put_line的输出信息输出至vsql的命令界面的屏幕上)。
set serveroutput=on;
示例1: 在匿名块中分布调用UTL_HTTP函数。
declare
req utl_http.req;
resp utl_http.resp;
res record;
value varchar2;
begin
req = utl_http.begin_request('172.16.19.117/jenkins/login');
utl_http.set_transfer_timeout(180);
utl_http.set_header(req, 'Content-Type', 'text/html');
utl_http.set_body_charset(req, 'UTF-8');
resp:=utl_http.get_response(req);
loop
res:=utl_http.read_line(resp, value, true);
value:=res.data;
raise notice '%',value;
end loop;
exception
when "utl_http.end_of_body" THEN
utl_http.end_response(resp);
raise notice 'end!!!';
utl_http.end_response(resp);
end;
/
执行成功后返回结果如下,返回网页HTML代码。
NOTICE:
NOTICE:
NOTICE:
NOTICE:
NOTICE:
NOTICE: <!DOCTYPE html><html lang="zh-CN"><head resURL="/jenkins/static/4aa2b6b3" data-rooturl="/jenkins" data-resurl="/jenkins/static/4aa2b6b3"><title>Sign in [Jenkins]</title><meta name="ROBOTS" content="NOFOLLOW"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="/jenkins/static/4aa2b6b3/css/simple-page.css" type="text/css"><link rel="stylesheet" href="/jenkins/static/4aa2b6b3/css/simple-page.theme.css" type="text/css"><link rel="stylesheet" href="/jenkins/static/4aa2b6b3/css/simple-page-forms.css" type="text/css"></head><body><div class="simple-page" role="main"><div class="modal login"><div id="loginIntroDefault"><div class="logo"></div><h1>Welcome to Jenkins!</h1></div><form method="post" name="login" action="j_acegi_security_check"><div class="formRow"><input autocorrect="off" name="j_username" id="j_username" placeholder="Username" type="text" class="normal" autocapitalize="off"></div><div class="formRow"><input name="j_password" placeholder="Password" type="password" class="normal"></div><input name="from" type="hidden"><div class="submit formRow"><input name="Submit" type="submit" value="Sign in" class="submit-button primary"></div><script type="text/javascript">document.getElementById('j_username').focus();var checkBoxClick=function(event){document.getElementById('remember_me').click();}</script><div class="Checkbox Checkbox-medium"><label class="Checkbox-wrapper"><input type="checkbox" id="remember_me" name="remember_me"><div class="Checkbox-indicator"><svg xmlns="http://www.w3.org/2000/svg" height="25" class="svg-icon check" focusable="false" viewBox="0 0 24 24" width="25"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"></path></svg></div><div class="Checkbox-text">Keep me signed in</div></label></div></form><div class="footer"></div></div></div> <div id="bitnami-banner" data-banner-id="bc38c"> <style>#bitnami-banner{z-index:100000;height:80px;padding:0;width:120px;background:transparent;position:fixed;right:0;bottom:0;border:0 solid #ededed}#bitnami-banner .bitnami-corner-image-div{position:fixed;right:0;bottom:0;border:0;z-index:100001;height:110px}#bitnami-banner .bitnami-corner-image-div .bitnami-corner-image{position:fixed;right:0;bottom:0;border:0;z-index:100001;height:110px}#bitnami-close-banner-button{height:12px;width:12px;z-index:10000000000;position:fixed;right:5px;bottom:65px;display:none;cursor:pointer}</style> <img id="bitnami-close-banner-button" src="/bitnami/images/close.png"/> <div class="bitnami-corner-image-div"> <a href="/bitnami/index.html" target="_blank"> <img class="bitnami-corner-image" alt="Bitnami" src="/bitnami/images/corner-logo.png"/> </a> </div> <script type="text/javascript" src="/bitnami/banner.js"></script> </div> </body></html>
NOTICE: end!!!
ANONYMOUS BLOCK EXECUTE
示例2: 分布调用begin_request函数,在read_line函数中指定删除换行符。
1、创建函数FN_HTTP_GET。
CREATE OR REPLACE FUNCTION FN_HTTP_GET (v_url VARCHAR2, method varchar2, remove boolean)
RETURN VARCHAR2
AS
BEGIN
DECLARE
req UTL_HTTP.REQ;
resp UTL_HTTP.RESP;
res record;
value varchar2;
v_text text;
BEGIN
v_text := '';
BEGIN
req := UTL_HTTP.BEGIN_REQUEST( url => v_url, method => method );
UTL_HTTP.SET_BODY_CHARSET(req, 'UTF-8');
UTL_HTTP.SET_HEADER(req, 'Content-Type', 'text/html');
resp := UTL_HTTP.GET_RESPONSE( req );
LOOP
res:=UTL_HTTP.READ_LINE( resp, value, remove);
value:=res.data;
v_text := v_text || value;
END LOOP;
UTL_HTTP.END_RESPONSE( resp );
UTL_HTTP.END_REQUEST( req );
EXCEPTION
WHEN "utl_http.end_of_body" THEN
UTL_HTTP.END_RESPONSE( resp );
WHEN OTHERS THEN
RAISE EXCEPTION '(%)', SQLERRM;
UTL_HTTP.END_RESPONSE(resp);
END;
return v_text;
END;
END;
/
2、调用FN_HTTP_GET函数。
select FN_HTTP_GET('http://172.16.19.117/jenkins/login','GET', true)from dual;
返回结果如下,返回相应的网页信息且删除了换行符。
fn_http_get
--------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------
<!DOCTYPE html><html lang="zh-CN"><head resURL="/jenkins/static/4aa2b6b3" data-rooturl="/jenkin
s" data-resurl="/jenkins/static/4aa2b6b3"><title>Sign in [Jenkins]</title><meta name="ROBOTS" content="NOFOLLO
W"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="/jenkins/s
tatic/4aa2b6b3/css/simple-page.css" type="text/css"><link rel="stylesheet" href="/jenkins/static/4aa2b6b3/css/
simple-page.theme.css" type="text/css"><link rel="stylesheet" href="/jenkins/static/4aa2b6b3/css/simple-page-f
orms.css" type="text/css"></head><body><div class="simple-page" role="main"><div class="modal login"><div id="
loginIntroDefault"><div class="logo"></div><h1>Welcome to Jenkins!</h1></div><form method="post" name="login"
action="j_acegi_security_check"><div class="formRow"><input autocorrect="off" name="j_username" id="j_username
" placeholder="Username" type="text" class="normal" autocapitalize="off"></div><div class="formRow"><input nam
e="j_password" placeholder="Password" type="password" class="normal"></div><input name="from" type="hidden"><d
iv class="submit formRow"><input name="Submit" type="submit" value="Sign in" class="submit-button primary"></d
iv><script type="text/javascript">document.getElementById('j_username').focus();var checkBoxClick=function(eve
nt){document.getElementById('remember_me').click();}</script><div class="Checkbox Checkbox-medium"><label clas
s="Checkbox-wrapper"><input type="checkbox" id="remember_me" name="remember_me"><div class="Checkbox-indicator
"><svg xmlns="http://www.w3.org/2000/svg" height="25" class="svg-icon check" focusable="false" viewBox="0 0 24
24" width="25"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"></path></svg></div><div class="Che
ckbox-text">Keep me signed in</div></label></div></form><div class="footer"></div></div></div> <div id="bitna
mi-banner" data-banner-id="bc38c"> <style>#bitnami-banner{z-index:100000;height:80px;padding:0;width:120px;ba
ckground:transparent;position:fixed;right:0;bottom:0;border:0 solid #ededed}#bitnami-banner .bitnami-corner-im
age-div{position:fixed;right:0;bottom:0;border:0;z-index:100001;height:110px}#bitnami-banner .bitnami-corner-i
mage-div .bitnami-corner-image{position:fixed;right:0;bottom:0;border:0;z-index:100001;height:110px}#bitnami-c
lose-banner-button{height:12px;width:12px;z-index:10000000000;position:fixed;right:5px;bottom:65px;display:non
e;cursor:pointer}</style> <img id="bitnami-close-banner-button" src="/bitnami/images/close.png"/> <div class
="bitnami-corner-image-div"> <a href="/bitnami/index.html" target="_blank"> <img class="bitnami-corn
er-image" alt="Bitnami" src="/bitnami/images/corner-logo.png"/> </a> </div> <script type="text/javascrip
t" src="/bitnami/banner.js"></script> </div> </body></html>
(1 row)
示例3: 调用READ_TEXT函数:根据请求url返回内容的字符集编码信息,解码并读取指定个数的字符存入指定的缓冲区中。
DECLARE
l_http_request utl_http.req;
l_http_response utl_http.resp;
l_text VARCHAR2(32767);
i int:=15;
BEGIN
l_http_request:=utl_http.begin_request('http://172.16.19.135/reviewboard/r/33797/','GET');
l_http_response:= utl_http.get_response(l_http_request);
BEGIN
dbms_output.put_line('--------------');
while i>0 LOOP
utl_http.read_text (l_http_response,l_text,100);
dbms_output.put_line(l_text);
i:=i-1;
END LOOP;
dbms_output.put_line('length' || length(l_text) );
EXCEPTION
WHEN"utl_http.end_of_body" THEN
RAISE NOTICE 'utl_http.end_of_body';
utl_http.end_response(l_http_response);
END;
EXCEPTION
WHEN OTHERS THEN
utl_http.end_response(l_http_response);
dbms_output.put_line('EXCEPTION');
RAISE;
END;
/
返回结果如下:
--------------
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=10; IE=9; IE=8; I
E=7; IE=EDGE" />
<title>【exbase_trunk】添加oracle2e100可转换列表关键字 | Review Request | Review Board</title
>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
<scri
pt type="text/javascript">
var AJAX_SERIAL = "1684897626",
TEMPLATE_SERIAL = "1497942185
",
SITE_ROOT = "/reviewboard/",
MANUAL_URL = 'https://www.reviewboard.org/docs/manua
l/2.5/',
STATIC_URLS = {
'rb/images/favicon_notify.ico': '/reviewboard/static/rb
/images/favicon_notify.43aac64f3b61.ico',
'rb/images/resize-grip.png': '/reviewboard/sta
tic/rb/images/resize-grip.b822a7e06419.png'
};
</script>
<link rel="shortcut icon" type
="image/x-icon" href="/reviewboard/static/rb/images/favicon.3161c840d49e.ico" />
<link rel="apple-
touch-icon-precomposed" type="image/png" href="/reviewboard/static/rb/images/apple-home-icon.fd8758a
2ebe3.png" />
<link href="/reviewboard/static/rb/css/common.min.4f75f99285e2.css" rel="stylesheet"
type="text/css" />
<link href="/reviewboard/static/rb/css/reviews.min.05b6d97ba305.css" rel="sty
lesheet" type="text/css" />
<style type="text/css">
.ew { background: #ee3434; }
</style>
<!--[if lt IE 7.]>
<style type="text/css">
body {
behavior: url("/reviewboard/static/l
ib/js/csshover2.40df985cb243.htc");
}
img,
table.sidebyside .commentflag,
.box.impo
length100
ANONYMOUS BLOCK EXECUTE
示例4: 调用request函数失败,捕获异常,并使用get_detailed_sqlerrm获取详细错误信息。
create or replace function test_exception(url varchar2) return number as
begin
declare
req varchar2;
v_http_content varchar2(2000);
v_error_content varchar2(500);
begin
begin
utl_http.set_transfer_timeout(10);
req = utl_http.request(url);
exception
when "utl_http.transfer_timeout" THEN
raise notice 'timeout!!';
v_error_content := substr(utl_http.get_detailed_sqlerrm(),0,500);
when "utl_http.init_failed" THEN
raise notice 'init_failed!!';
v_error_content := substr(utl_http.get_detailed_sqlerrm(),0,500);
when "utl_http.request_failed" THEN
raise notice 'request_failed!!';
v_error_content := substr(utl_http.get_detailed_sqlerrm(),0,500);
end;
return v_error_content;
end;
end;
/
超时:
select test_exception('http://172.16.101.22:8088/notice');
返回结果如下:
NOTICE: timeout!! CONTEXT: referenced column: test_exception ERROR: invalid input syntax for type numeric: "<urlopen error timed out>" CONTEXT: PL/pgSQL function public.test_exception(varchar) while casting return value to function's return type referenced column: test_exception
初始化失败:
select test_exception('http://14.215.177.38:443/home');
返回结果如下:
NOTICE: init_failed!! CONTEXT: referenced column: test_exception ERROR: invalid input syntax for type numeric: "ValueError: invalid literal for int() with base 10: 'www.baidu.com' During handling of the above exception, another exception occurred: http.client.InvalidURL: nonnumeric port: 'www.baidu.com' " CONTEXT: PL/pgSQL function public.test_exception(varchar) while casting return value to function's return type referenced column: test_exception