ACL配置必须由DBA执行,精确到域名和端口;POST需设正确Content-Length(用LENGTHB);响应读取须异常处理并显式释放连接;HTTPS需Oracle Wallet,不可禁用校验。

ACL权限配置必须由DBA执行且精确到域名和端口
没配ACL,UTL_HTTP 一发请求就报 ORA-29273 和 ORA-24247,这不是代码问题,是数据库级拦截。即使目标是 localhost 或内网地址,也得显式授权。
常见错误包括:
- 用
'example.com'授权却调用'api.example.com'—— host 必须完全匹配 - HTTPS 目标写了
lower_port => 440, upper_port => 450,但 Oracle 要求端口范围必须精确覆盖实际使用的443 - 用角色名(如
'APP_ROLE')代替具体用户名作为principal,ACL 不生效 - 配完没
COMMIT,或没查DBA_NETWORK_ACLS和DBA_NETWORK_ACL_PRIVILEGES确认已绑定
正确做法是 DBA 执行三步:
DBMS_NETWORK_ACL_ADMIN.create_acl(acl => '/sys/acls/api_call.xml', principal => 'MYUSER', is_grant => TRUE, privilege => 'connect')-
DBMS_NETWORK_ACL_ADMIN.add_privilege(acl => '/sys/acls/api_call.xml', principal => 'MYUSER', is_grant => TRUE, privilege => 'resolve')(DNS 解析必需) DBMS_NETWORK_ACL_ADMIN.assign_acl(acl => '/sys/acls/api_call.xml', host => 'api.example.com', lower_port => 443, upper_port => 443)
POST JSON 请求必须手动设 Content-Length 且用 LENGTHB
Content-Length 是字节数,不是字符数。UTF-8 下中文一个字占 3 字节,LENGTH('你好') 返回 2,但服务端要的是 6 —— 写错直接导致 400 或 body 截断。
关键点:
- 必须在
UTL_HTTP.write_text()或write_raw()之前调UTL_HTTP.set_header(req, 'Content-Length', ...),顺序颠倒无效 - 对含中文的
VARCHAR2,用LENGTHB(json_body);若用CLOB,先DBMS_LOB.getlength() - 不要信老教程里写的
UTL_HTTP.set_body()—— 这个函数根本不存在 - 若数据库字符集是
ZHS16GBK,write_text会按 GBK 发送,对方很可能解析失败;应转 UTF-8 后用write_raw(UTL_RAW.cast_to_raw(CONVERT(..., 'AL32UTF8', 'ZHS16GBK')))
响应读取不加异常处理会卡死或丢数据
UTL_HTTP.get_response() 只返回状态码,不带响应体。如果服务端返回空响应、流提前关闭或网络中断,不包异常就会抛 UTL_HTTP.end_of_body 导致过程终止,且 end_response 没执行,连接泄漏。
安全写法必须用循环 + 异常捕获:
- 超时默认仅 60 秒,外部 API 响应慢时必设
UTL_HTTP.set_transfer_timeout(120)(单位秒),且必须在begin_request()之后、get_response()之前调 - 读响应必须用
BEGIN ... EXCEPTION WHEN UTL_HTTP.end_of_body THEN ... END包裹read_line或read_text循环 - 每次读完都要检查
resp.status_code,200 以外(比如 401、429)不能跳过,否则逻辑误判 - 务必在
EXCEPTION分支中调UTL_HTTP.end_response(resp)和UTL_HTTP.end_request(req),否则下次调用可能因连接未释放而失败
HTTPS 自签名或旧 TLS 证书需 Wallet,不能关校验
Oracle 19c 默认拒绝自签名证书、SHA-1 签名或 TLS 1.0/1.1 的 HTTPS 站点。试图用 UTL_HTTP.set_wallet(NULL) 或绕过验证会失败 —— Oracle 不提供禁用 SSL 校验的开关。
真实可行路径只有一条:
- 用
orapki wallet create -wallet /path/to/wallet -auto_login创建 Oracle Wallet - 把目标服务的 CA 证书或自签名证书导入:
orapki wallet add -wallet /path/to/wallet -trusted_cert -cert server.crt - 在 PL/SQL 中调
UTL_HTTP.set_wallet('file:/path/to/wallet', 'wallet_pwd'),路径必须是数据库服务器本地可读路径 - 注意:Wallet 路径不能用 UNC 或相对路径;密码不能含特殊字符(如
@)否则解析失败
最易被忽略的是 Wallet 权限 —— 数据库 OS 用户必须有读取 wallet 目录及文件的权限,否则报错不提示具体原因,只卡在连接阶段。











