VastbaseG100

基于openGauss内核开发的企业级关系型数据库。

Menu

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