#UTL_HTTP
UTL_HTTP包是用于HTTP客户端操作的内置包,包含了一组子程序、常量及数据结构。用户可以通过UTL_HTTP从Web服务器上获取数据,或者向HTTP服务器发送数据。
使用UTL_HTTP包时需保证数据库服务器到HTTP服务器网络需连通。
因数据库服务器访问HTTP服务器需要消耗网络资源,对数据库运行性能可能产生影响,请谨慎评估后通过sys用户给操作用户赋权。
GRANT EXECUTE ON UTL_HTTP TO user_name;
# 预定义常量
UTL_HTTP系统包定义了一组常量,供UTL_HTTP高级包相关函数及子程序调用。下表为详细信息。
| 名称 | 值 | 描述 |
|---|---|---|
| HTTP_VERSION_1_0 | 'HTTP/1.0' | HTTP 1.0 |
| HTTP_VERSION_1_1 | 'HTTP/1.1' | HTTP 1.1 |
| DEFAULT_HTTP_PORT | 80 | Web服务器或代理服务器侦听的默认TCP/IP 80端口 |
| DEFAULT_HTTPS_PORT | 443 | HTTPS Web服务器监听的默认TCP/IP 443端口 |
| HTTP_CONTINUE | 100 | 客户端应继续其请求。此临时响应用于通知客户端,请求的初始部分已收到,并且尚未被服务器拒绝。 |
| HTTP_SWITCHING_PROTOCOLS | 101 | 服务器理解并愿意遵循客户端通过升级消息头字段发出的请求,更改此连接上使用的应用协议。服务器将在结束101响应的空行之后立即将协议切换到响应升级头字段中定义的协议。 |
| HTTP_OK | 200 | 请求成功。响应返回的信息取决于请求中使用的方法 |
| HTTP_CREATED | 201 | 请求已得到满足并导致新资源被创建。 |
| HTTP_ACCEPTED | 202 | 请求已被接受处理,但尚未完成。该请求最终可能会被处理,也可能不会被处理,因为实际处理时可能会被拒绝。 |
| HTTP_NON_AUTHOR | 203 | 实体头中返回的元信息不是源服务器提供的最终集合,而是从本地或第三方副本收集的。 |
| HTTP_NO_CONTENT | 204 | 服务器已完成请求但不需要返回实体主体,并且可能希望返回更新的元信息。 |
| HTTP_RESET_CONT | 205 | 服务器已完成请求,用户代理应重置导致发送请求的文档视图。响应中不得包含实体。 |
| HTTP_PARTIAL_CONTENT | 206 | 服务器已完成对资源的部分GET请求。 |
| HTTP_MULTIPLE_CHOICES | 300 | 所请求的资源对应于一组表示中的任何一个,每个表示都有其自己的特定位置,并且正在提供代理驱动的协商信息,以便用户(或用户代理)可以选择首选表示并将其请求重定向到该位置。 |
| HTTP_MOVED_PERMANENTLY | 301 | 所请求的资源已被分配一个新的永久URI,并且对该资源的任何未来引用都应使用返回的URI之一。 |
| HTTP_FOUND | 302 | 请求的资源暂时驻留在不同的URI下。 |
| HTTP_SEE_OTHER | 303 | 可以在不同的URI下找到对请求的响应,并且应该使用该资源上的 GET 方法进行检索。 |
| HTTP_NOT_MODIFIED | 304 | 如果客户端执行了有条件的GET请求并且允许访问,但文档尚未修改,则服务器将使用此状态代码进行响应。 |
| HTTP_USE_PROXY | 305 | 请求的资源必须通过Location字段指定的代理进行访问。Location 字段给出了代理的 URI。 |
| HTTP_TEMPORARY_REDIRECT | 307 | 请求的资源暂时驻留在不同的URI下。 |
| HTTP_BAD_REQUEST | 400 | 由于语法错误,服务器无法理解该请求。 |
| HTTP_UNAUTHORIZED | 401 | 该请求需要用户身份验证。客户端可以使用合适的Authorization标头字段重复该请求。如果请求中已包含授权凭证,则401响应表示针对这些凭证的授权已被拒绝。 |
| HTTP_PAYMENT_REQUIRED | 402 | 暂未使用 |
| HTTP_FORBIDDEN | 403 | 服务器理解了该请求,但拒绝执行。 |
| HTTP_NOT_FOUND | 404 | 服务器未找到任何与请求 URI 匹配的内容。 |
| HTTP_NOT_ACCEPTABLE | 406 | 请求所标识的资源仅能够生成具有根据请求中发送的接受标头不可接受的内容特征的响应实体。 |
| HTTP_PROXY_AUTH_REQUIRED | 407 | 此代码类似于401(未授权),但表示客户端必须首先向代理进行身份验证。 |
| HTTP_REQUEST_TIME_OUT | 408 | 客户端未在服务器准备等待的时间内发出请求。 |
| HTTP_CONFLICT | 409 | 由于与资源的当前状态冲突,无法完成请求。 |
| HTTP_GONE | 410 | 所请求的资源在服务器上不再可用,并且不知道转发地址。 |
| HTTP_LENGTH_REQUIRED | 411 | 服务器拒绝接受未定义的请求Content-Length。 |
| HTTP_PRECONDITION_FAILED | 412 | 在服务器上测试时,请求标头字段中给出的一个或多个先决条件被评估为 false |
| HTTP_REQUEST_ENTITY_TOO_LARGE | 413 | 服务器拒绝处理请求,因为请求实体大于服务器愿意或能够处理的大小。 |
| HTTP_REQUEST_URI_TOO_LARGE | 414 | 服务器拒绝为该请求提供服务,因为请求URI的长度超出了服务器愿意解释的长度。 |
| HTTP_UNSUPPORTED_MEDIA_TYPE | 415 | 服务器拒绝为该请求提供服务,因为请求的实体的格式不受请求的资源和请求的方法支持。 |
| HTTP_REQ_RANGE_NOT_SATISFIABLE | 416 | 如果请求包含Range请求标头字段,并且此字段中的任何范围说明符值均未与所选资源的当前范围重叠,并且请求不包含If-Range请求标头字段,则服务器返回带有此状态代码的响应。 |
| HTTP_EXPECTATION_FAILED | 417 | 该服务器无法满足 Expect 请求标头字段中给出的期望,或者,如果服务器是代理,则服务器有明确的证据表明下一跳服务器无法满足该请求。 |
| HTTP_NOT_IMPLEMENTED | 501 | 服务器不支持满足请求所需的功能。 |
| HTTP_BAD_GATEWAY | 502 | 服务器在充当网关或代理时,在尝试完成请求时从其访问的上游服务器收到了无效响应 |
| HTTP_SERVICE_UNAVAILABLE | 503 | 由于服务器暂时过载或维护,服务器目前无法处理该请求。 |
| HTTP_GATEWAY_TIME_OUT | 504 | 该服务器在充当网关或代理时,未从URI(例如HTTP、FTP、LDAP)指定的上游服务器或尝试完成请求时需要访问的其他辅助服务器(例如DNS)收到及时响应。 |
| HTTP_VERSION_NOT_SUPPORTED | 505 | 服务器不支持或拒绝支持请求消息中使用的HTTP协议版本 |
# 子程序说明
# BEGIN_REQUEST
UTL_HTTP.BEGIN_REQUEST
(
URL IN VARCHAR,
Method IN VARCHAR DEFAULT 'GET',
HTTP_VERSION IN VARCHAR DEFAULT NULL,
REQUEST_CONTEXT IN REQUEST_CONTEXT_KEY DEFAULT NULL,
HTTP_HOST IN VARCHAR DEFAULT NULL)
RETURN UTL_HTTP.REQ;
BEGIN_REQUEST函数将HTTP请求初始化,生成HTTP请求体结构将用于后续接口函数中。
| 参数 | 描述 |
|---|---|
| URL | 待访问的URL地址。 |
| Method | 指定HTTP请求方法。当前支持如下方法,请根据HTTP服务端开放的端口进行配置,不配置时通过GET方法进行进行连接请求。 - GET - POST - PUT - PATCH - DELETE |
| HTTP_VERSION | 发送请求的 HTTP 协议版本。当前支持HTTP1.0/1.1 |
| REQUEST_CONTEXT | 请求体上下文key值。仅语法兼容,无实际含义。 |
| HTTP_HOST | HTTP请求的主机名,默认值为NULL,为NULL时使用URL作为主机名。 |
# END_RESPONSE
UTL_HTTP.END_RESPONSE
(
RESP IN OUT UTL_HTTP.RESP);
结束HTTP请求,清理HTTP资源。对于设置了持久化连接的请求,无法通过END_RESPONSE关闭连接。
# GET_BUFFER_SIZE
UTL_HTTP.GET_BUFFER_SIZE
(
REQ IN UTL_HTTP.REQ,
SIZE OUT INTEGER)
RETURN BUFFER_SIZE;
获取HTTP收发数据可用的缓存大小。
| 参数 | 描述 |
|---|---|
| REQ | HTTP请求头结构 |
| SIZE | HTTP收发数据实际可用的缓存大小 |
# GET_DETAILED_SQLERRM
UTL_HTTP.GET_DETAILED_SQLERRM ()
RETURN DETAILED_SQLERRM;
获取HTTP请求错误的详细返回信息,数据类型为VARCHAR。
# GET_RESPONSE
UTL_HTTP.GET_RESPONSE
(
REQ IN UTL_HTTP.REQ,
RETURN_INFO_RESPONSE IN BOOLEAN DEFAULT FALSE)
RETURN UTL_HTTP.RESP;
获取HTTP的响应体,用于判断HTTP请求的状态码等信息。
| 参数 | 描述 |
|---|---|
| REQ | HTTP请求头结构 |
| RETURN_INFO_RESPONSE | 是否返回1**状态码。仅语法兼容,无实际含义。 |
# GET_TRANSFER_TIMEOUT
UTL_HTTP.GET_TRANSFER_TIMEOUT
(
TIMEOUT OUT INTEGER DEFAULT NULL
);
获取全局HTTP请求超时时间。
| 参数 | 描述 |
|---|---|
| TIMEOUT | 超时时间(秒) |
# READ_LINE
UTL_HTTP.READ_LINE
(
RESP IN OUT UTL_HTTP.RESP,
DATA OUT VARCHAR,
REMOVE_CRLF IN BOOL DEFAULT FALSE
);
按行从HTTP响应体中读取数据。
| 参数 | 描述 |
|---|---|
| RESP | HTTP的响应结构 |
| DATA | HTTP响应体数据 |
| REMOVE_CRLF | 是否删除换行符 |
# READ_RAW
UTL_HTTP.READ_RAW
(
RESP IN OUT UTL_HTTP.RESP,
DATA OUT RAW,
LEN IN INTEGER DEFAULT NULL);
按RAW类型读HTTP响应体数据。
| 参数 | 描述 |
|---|---|
| RESP | HTTP的响应结构 |
| DATA | HTTP响应体数据 |
| LEN | 读取数据的字节长度,默认长度为NULL |
# READ_TEXT
UTL_HTTP.READ_TEXT
(
RESP IN OUT UTL_HTTP.RESP,
DATA OUT VARCHAR,
LEN IN INTEGER DEFAULT NULL
);
从HTTP响应缓冲区中读取Body信息。
| 参数 | 描述 |
|---|---|
| RESP | HTTP的响应结构 |
| DATA | HTTP响应体数据 |
| LEN | 读取数据的字节长度,默认长度为NULL |
# WRITE_LINE
UTL_HTTP.WRITE_LINE
(
REQ IN OUT UTL_HTTP.REQ,
DATA IN VARCHAR);
以文本格式写入一行数据到HTTP请求体。
| 参数 | 描述 |
|---|---|
| REQ | HTTP请求头结构 |
| DATA | HTTP请求体数据 |
# WRITE_RAW
UTL_HTTP.WRITE_RAW
(
REQ IN OUT UTL_HTTP.REQ,
DATA IN RAW);
按RAW类型写入HTTP请求体数据。
| 参数 | 描述 |
|---|---|
| REQ | HTTP请求头结构 |
| DATA | HTTP请求体数据 |
# WRITE_TEXT
UTL_HTTP.WRITE_TEXT
(
REQ IN OUT UTL_HTTP.REQ,
DATA IN VARCHAR);
按文本格式写入HTTP请求体信息,常结合PUT/POST/DELETE等HTTP方法使用。
| 参数 | 描述 |
|---|---|
| REQ | HTTP请求头结构 |
| DATA | HTTP请求体数据 |
# SET_AUTHENTICATION
UTL_HTTP.SET_AUTHENTICATION
(
REQ IN OUT UTL_HTTP.REQ,
USERNAME IN VARCHAR,
PASSWORD IN VARCHAR,
SCHEME IN VARCHAR DEFAULT 'Basic',
FOR_PROXY IN BOOL DEFAULT FALSE
);
设置HTTP认证信息。
| 参数 | 描述 |
|---|---|
| REQ | HTTP请求头结构 |
| USERNAME | 用于认证的用户名 |
| PASSWORD | 用于认证的密码 |
| SCHEME | 认证模式, 默认为Basic |
| FOR_PROXY | 是否用于代理服务器的认证。仅语法兼容,无实际含义。 |
# SET_BODY_CHARSET
UTL_HTTP.SET_BODY_CHARSET
( CHARSET IN VARCHAR DEFAULT NULL);
UTL_HTTP.SET_BODY_CHARSET
( CHARSET IN VARCHAR DEFAULT NULL,
REQ IN OUT UTL_HTTP.REQ);
UTL_HTTP.SET_BODY_CHARSET
( CHARSET IN VARCHAR DEFAULT NULL,
RESP IN OUT UTL_HTTP.RESP);
设置HTTP请求体、响应体的字符集信息,主要用于请求和响应的BODY字符集。
| 参数 | 描述 |
|---|---|
| CHARSET | 设置整个HTTP请求的字符集信息 |
| REQ | HTTP请求头结构 |
| RESP | HTTP的响应结构 |
# SET_BUFFER_SIZE
UTL_HTTP.SET_BUFFER_SIZE
(
REQ IN UTL_HTTP.REQ,
SIZE IN INTEGER);
设置HTTP收发数据可用的缓存大小,默认为2M。
| 参数 | 描述 |
|---|---|
| REQ | HTTP请求头结构 |
| SIZE | 设置HTTP收发数据可用的缓存大小 |
# SET_DETAILED_EXCP_SUPPORT
UTL_HTTP.SET_DETAILED_EXCP_SUPPORT
(
ENABLE IN BOOL DEFAULT FALSE);
设置是否返回详细的错误信息,默认FALSE为不返回。
# SET_HEADER
UTL_HTTP.SET_HEADER
(
REQ IN OUT UTL_HTTP.REQ,
NAME IN VARCHAR,
VALUE IN VARCHAR DEFAULT NULL
);
设置HTTP请求头信息。
| 参数 | 描述 |
|---|---|
| REQ | HTTP请求头结构 |
| NAME | HTTP请求头的名称 |
| VALUE | HTTP请求头的值 |
# SET_PERSISTENT_CONN_SUPPORT
UTL_HTTP.SET_PERSISTENT_CONN_SUPPORT
( ENABLE IN BOOL DEFAULT FALSE,
MAX_CONNS IN INTEGER DEFAULT 0,
REQ IN OUT UTL_HTTP.REQ);
设置HTTP持久化连接。该函数当前仅为语法兼容,无实际含义。
| 参数 | 描述 |
|---|---|
| ENABLE | 是否持久化连接 |
| MAX_CONNS | 最大连接数 |
| REQ IN OUT | 需要建立持久化连接的HTTP请求体 |
# SET_TRANSFER_TIMEOUT
UTL_HTTP.SET_TRANSFER_TIMEOUT
(
REQ IN OUT UTL_HTTP.REQ,
TIMEOUT IN INTEGER DEFAULT 60
);
设置全局HTTP请求超时时间或设置单个请求的超时时间。
| 参数 | 描述 |
|---|---|
| REQ | HTTP请求头结构 |
| TIMEOUT | 超时时间(秒),默认为60秒。 |
# 示例
示例一:常用用法示例
DECLARE
req UTL_HTTP.REQ;
resp UTL_HTTP.RESP;
l_url VARCHAR2(100) := 'http://localhost:5000/api/get';
l_mothod VARCHAR2(100) := 'get';
l_buffer VARCHAR2(4000);
BEGIN
-- BEGIN a HTTP request
req := UTL_HTTP.BEGIN_REQUEST(l_url, l_mothod, 'HTTP/1.1');
UTL_HTTP.SET_BODY_CHARSET(req, 'UTF8');
UTL_HTTP.set_header(req, 'Accept', 'application/json');
-- Get the HTTP response
resp := UTL_HTTP.GET_RESPONSE(req);
-- Print the status OF the HTTP response
DBMS_OUTPUT.put_line(l_mothod|| 'The status of the HTTP response is: ' || resp.status_code || ' ' || resp.reason_phrase);
-- Confirm the response
UTL_HTTP.READ_TEXT(resp, l_buffer, 4000);
DBMS_OUTPUT.PUT_LINE(' Response: ' || l_buffer);
-- CLOSE the response
UTL_HTTP.END_RESPONSE(resp);
DBMS_OUTPUT.put_line(l_mothod || 'The HTTP request processing is completed.');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error: ' || SQLERRM);
UTL_HTTP.END_RESPONSE(resp);
END;
/
--result
get The status of the HTTP response is: 200 OK
Response: {
"data": {
"secret": "Top Secret Data"
},
"message": "Access granted"
}
getThe HTTP request processing is completed.
示例二:获取响应之后不关闭响应,如重复执行打开的次数超过设定值(5次)则无法继续响应。
DECLARE
req UTL_HTTP.REQ;
resp UTL_HTTP.RESP;
l_url VARCHAR2(100) := 'http://localhost:5000/api/get1';
l_mothod VARCHAR2(100) := 'get';
l_api_key VARCHAR2(100) := 'secret123';
l_buffer VARCHAR2(32767);
BEGIN
-- BEGIN a HTTP request
req := UTL_HTTP.BEGIN_REQUEST(l_url, l_mothod, 'HTTP/1.1');
UTL_HTTP.SET_BODY_CHARSET(req, 'UTF8');
UTL_HTTP.set_header(req, 'X-API-Key', l_api_key); -- SET API Key
UTL_HTTP.set_header(req, 'Accept', 'application/json');
-- Get the HTTP response
resp := UTL_HTTP.GET_RESPONSE(req);
-- Print the status OF the HTTP response
DBMS_OUTPUT.put_line(l_mothod|| 'The status of the HTTP response is: ' || resp.status_code || ' ' || resp.reason_phrase);
-- Confirm the response
UTL_HTTP.READ_TEXT(resp, l_buffer, 32767);
DBMS_OUTPUT.PUT_LINE(' Response: ' || l_buffer);
DBMS_OUTPUT.put_line(l_mothod || 'The HTTP request processing is completed.');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error: ' || SQLERRM);
UTL_HTTP.END_RESPONSE(resp);
END;
28 29 30 31 32 33 /
Error: YAS-06869 too many open requests or responses
# 异常说明
| 名称 | 错误码 | 描述 |
|---|---|---|
| init_failed | 6857 | HTTP请求初始化异常 |
| request_failed | 6858 | 请求执行失败 |
| bad_argument | 6859 | 传递给接口的参数不正确 |
| bad_url | 6860 | 请求的URL格式不正确 |
| protocol_error | 6861 | 与Web服务器通信时发生HTTP协议错误 |
| unknown_scheme | 6862 | 请求的URL的方案未知 |
| header_not_found | 6863 | 未找到请求头 |
| end_of_body | 6864 | HTTP响应主体已结束 |
| illegal_call | 6865 | 当前HTTP请求状态是一个非法的UTL_HTTP调用 |
| http_redirect_error | 6866 | HTTP请求过程中重定向异常 |
| http_client_error | 6867 | 使用GET_RESPONSE函数时,返回4xx范围内的响应状态码表示客户端发生错误;或者在使用begin_request函数通过HTTP代理发出HTTPS请求时收到了HTTP代理返回了4xx范围内的状态码。 |
| http_server_error | 6868 | 使用GET_RESPONSE函数时,返回5xx范围内的响应状态码表示客户端发生错误;或者在使用begin_request函数通过HTTP代理发出HTTPS请求时收到了HTTP代理返回了5xx范围内的状态码。 |
| too_many_requests | 6869 | 开放的HTTP请求或响应过多 |
| partial_multibyte_char | 6870 | 未读取完整字符,在响应主体末尾发现部分多字节字符 |
| transfer_timeout | 6871 | 未读取任何数据并且发生读取超时 |
| network_access_denied | 6872 | 远程网络主机拒绝访问 |
DECLARE
l_url VARCHAR2(2000);
l_response CLOB;
l_http_req UTL_HTTP.REQ;
l_http_resp UTL_HTTP.RESP;
l_buffer VARCHAR2(32767);
l_status_code NUMBER;
l_line NUMBER;
l_remove_crlf BOOLEAN := null;
BEGIN
DBMS_OUTPUT.PUT_LINE('=== TEST 1.1: Basic http request read line 3 ===');
l_url := 'http://127.0.0.1:8080/text/charset4';
l_http_req := UTL_HTTP.BEGIN_REQUEST(l_url, 'GET');
l_http_resp := UTL_HTTP.GET_RESPONSE(l_http_req);
UTL_HTTP.SET_BODY_CHARSET(l_http_resp, 'GB18030');
-- 获取状态码
l_status_code := l_http_resp.STATUS_CODE;
DBMS_OUTPUT.PUT_LINE('status code: ' || l_status_code);
-- 读取响应内容
l_line := 1;
l_response := EMPTY_CLOB;
LOOP
l_remove_crlf := CASE
WHEN l_remove_crlf IS NULL THEN true
WHEN l_remove_crlf THEN false
ELSE null
END;
UTL_HTTP.READ_LINE(l_http_resp, l_buffer, l_remove_crlf);
DBMS_OUTPUT.PUT_LINE(l_line || ': ' || l_buffer);
l_line := l_line + 1;
l_response := l_response || l_buffer;
END LOOP;
UTL_HTTP.END_RESPONSE(l_http_resp);
EXCEPTION
WHEN UTL_HTTP.PARTIAL_MULTIBYTE_CHAR THEN
DBMS_OUTPUT.PUT_LINE('PARTIAL_MULTIBYTE_CHAR: ' || SQLERRM);
DBMS_OUTPUT.PUT_LINE('Response data(head 500): ' || SUBSTR(l_response, 1, 500));
UTL_HTTP.END_RESPONSE(l_http_resp);
END;
/
=== TEST 1.1: Basic http request read line 3 ===
status code: 200
PARTIAL_MULTIBYTE_CHAR: YAS-06870 partial multibyte character
Response data(head 500):

