使用PL/SQL调用REST API时请求体未被识别的问题排查
问题描述
我是论坛新手,正在学习使用PL/SQL调用REST API。尝试调用RapidAPI提供的免费weatherapi-com接口,但服务器无法识别请求参数。相同请求在Postman中可正常执行,推测问题出在PL/SQL代码中。
存储过程代码
Create Or Replace Procedure TEST_REST_API ( PURL IN VARCHAR2 ) is req utl_http.req; res utl_http.resp; url varchar2(4000) := PURL; buffer varchar2(32767); content varchar2(8000); begin dbms_output.put_line('START'); UTL_TCP.close_all_connections; DBMS_OUTPUT.put_line('2'); UTL_HTTP.set_wallet('file:/u01/app/oracle/product/11.2.0/db_1/wallet/rapidapi','wallet123'); DBMS_OUTPUT.put_line('3'); UTL_HTTP.CLEAR_COOKIES(); content := '{"q":"autp:ip"}'; --content := ''; dbms_output.put_line('content '||content); req := utl_http.begin_request(url, 'GET',' HTTP/1.1'); utl_http.set_header(req, 'X-RapidAPI-Key', 'af1e7931bamsh3ac102afa8fef68p100423jsn8d4d3cc1325b'); utl_http.set_header(req, 'X-RapidAPI-Host', 'weatherapi-com.p.rapidapi.com'); utl_http.set_header(req, 'Content-Length', length(content)); utl_http.set_header(req, 'User-Agent', 'mozilla/4.0'); --utl_http.set_header(req, 'user-agent', 'PostmanRuntime/7.29.2'); utl_http.set_header(req, 'Content-Type', 'application/json'); utl_http.set_header(req, 'Connection','keep-alive'); --utl_http.set_header(req, 'Accept','*/*'); --utl_http.write_text(req, content); utl_http.write_text(req, content); --utl_http.write_text(req,''); --insert into wstemp values (req); res := utl_http.get_response(req); -- process the response from the HTTP call begin loop utl_http.read_line(res, buffer,TRUE); dbms_output.put_line(buffer); end loop; dbms_output.put_line('Response XML:'|| cast(x_clob as varchar2)); utl_http.end_response(res); exception when utl_http.end_of_body then utl_http.end_response(res); end; end;
执行脚本
BEGIN TEST_REST_API ( 'https://weatherapi-com.p.rapidapi.com/ip.json' ); END; /
服务器返回响应
{"error":{"code":1003,"message":"Parameter q is missing."}}
解决方法
问题根源有两个:
- GET请求不支持通过请求体传参:你当前用GET请求却尝试通过
utl_http.write_text写入JSON请求体,但绝大多数REST API的GET接口只会读取URL查询字符串中的参数,不会解析请求体。Postman能正常执行,大概率是你在Postman里把q参数放在了URL查询参数中,而非请求体。 - JSON格式与拼写错误:你写的
'{"q":"autp:ip"}'是HTML转义后的格式,PL/SQL中应直接写'{"q":"auto:ip"}',且你还把auto误写为autp。
针对该接口,正确做法是将q参数拼接到URL的查询字符串中,修改后的代码如下:
修改后的存储过程
Create Or Replace Procedure TEST_REST_API ( PURL IN VARCHAR2, P_Q_PARAM IN VARCHAR2 DEFAULT 'auto:ip' ) is req utl_http.req; res utl_http.resp; url_with_param varchar2(4000); buffer varchar2(32767); begin dbms_output.put_line('START'); UTL_TCP.close_all_connections; DBMS_OUTPUT.put_line('2'); UTL_HTTP.set_wallet('file:/u01/app/oracle/product/11.2.0/db_1/wallet/rapidapi','wallet123'); DBMS_OUTPUT.put_line('3'); UTL_HTTP.CLEAR_COOKIES(); -- 拼接查询参数到URL,用utl_url.escape处理特殊字符 url_with_param := PURL || '?q=' || utl_url.escape(P_Q_PARAM); dbms_output.put_line('Final URL: ' || url_with_param); req := utl_http.begin_request(url_with_param, 'GET','HTTP/1.1'); utl_http.set_header(req, 'X-RapidAPI-Key', 'af1e7931bamsh3ac102afa8fef68p100423jsn8d4d3cc1325b'); utl_http.set_header(req, 'X-RapidAPI-Host', 'weatherapi-com.p.rapidapi.com'); utl_http.set_header(req, 'User-Agent', 'mozilla/4.0'); utl_http.set_header(req, 'Connection','keep-alive'); res := utl_http.get_response(req); -- 处理响应 begin loop utl_http.read_line(res, buffer,TRUE); dbms_output.put_line(buffer); end loop; utl_http.end_response(res); exception when utl_http.end_of_body then utl_http.end_response(res); end; end;
修改后的执行脚本
BEGIN TEST_REST_API ( 'https://weatherapi-com.p.rapidapi.com/ip.json' ); END; /
额外注意事项:
- 调用GET接口严格遵循REST规范,用查询字符串传递参数,避免请求体传参。
- 用
utl_url.escape处理参数值,防止特殊字符破坏URL格式。 - 仔细检查参数拼写,避免低级错误。
内容的提问来源于stack exchange,提问作者Faheem Ahmed Shaik
相关产品推荐
相关产品推荐

