如何去除Oracle中UTL_HTTP.read_text响应的HTTP头信息
解决UTL_HTTP.read_text读取WSDL响应时混入HTTP头的问题
嘿,我之前也踩过一模一样的坑!咱们来拆解问题,然后彻底搞定它:
你用UTL_HTTP.read_text替代UTL_HTTP.read_line来处理超长请求数据,这完全符合Ask Tom的建议,但为啥前者会带出HTTP头相关内容(比如那个烦人的“Servlet/2.5 JSP/2.1”),后者却不会?
核心原因很简单:UTL_HTTP.read_line默认会自动跳过所有HTTP响应头,直接定位到响应体开始读取;但read_text没有这个默认行为——它会从当前的读取位置开始,把所有内容(包括还没处理的头信息)一股脑读出来。
解决步骤
要搞定这个问题,关键是先显式处理完所有HTTP响应头,再读取响应体,具体操作如下:
1. 先跳过所有HTTP响应头
我们可以通过循环调用UTL_HTTP.next_header遍历所有响应头,直到触发end_of_headers异常(这说明头已经处理完,接下来就是响应体了):
BEGIN LOOP UTL_HTTP.next_header(l_http_resp); END LOOP; EXCEPTION WHEN UTL_HTTP.end_of_headers THEN NULL; -- 到头了,直接退出循环即可 END;
2. 读取纯响应体内容
处理完头之后,再用UTL_HTTP.read_text循环读取响应体,把内容写入CLOB:
LOOP BEGIN UTL_HTTP.read_text(l_http_resp, l_text, 32767); DBMS_LOB.writeappend(l_ws_response, LENGTH(l_text), l_text); EXCEPTION WHEN UTL_HTTP.end_of_body THEN EXIT; -- 读取完所有响应体,退出循环 END; END LOOP;
完整示例代码
把这些步骤整合到你的程序里,完整代码大概是这样:
DECLARE l_http_resp UTL_HTTP.RESPONSE; l_text VARCHAR2(32767); l_ws_response CLOB; BEGIN -- 初始化临时CLOB存储响应内容 DBMS_LOB.createtemporary(l_ws_response, TRUE); -- 假设你已经完成请求发送,获取了l_http_resp对象 -- 第一步:跳过所有HTTP响应头 BEGIN LOOP UTL_HTTP.next_header(l_http_resp); END LOOP; EXCEPTION WHEN UTL_HTTP.end_of_headers THEN NULL; END; -- 第二步:循环读取响应体内容 LOOP BEGIN UTL_HTTP.read_text(l_http_resp, l_text, 32767); DBMS_LOB.writeappend(l_ws_response, LENGTH(l_text), l_text); EXCEPTION WHEN UTL_HTTP.end_of_body THEN EXIT; END; END LOOP; -- 这里可以处理你的响应内容了,比如解析XML -- DBMS_OUTPUT.put_line(l_ws_response); -- 清理资源 DBMS_LOB.freetemporary(l_ws_response); UTL_HTTP.end_response(l_http_resp); EXCEPTION WHEN OTHERS THEN -- 异常处理:确保关闭响应对象和释放CLOB IF UTL_HTTP.response_p(l_http_resp) THEN UTL_HTTP.end_response(l_http_resp); END IF; IF DBMS_LOB.istemporary(l_ws_response) THEN DBMS_LOB.freetemporary(l_ws_response); END IF; RAISE; END; /
额外注意点
如果你的响应是分块编码的(比如响应头里有Transfer-Encoding: chunked),不用担心,Oracle 11g及以上版本的UTL_HTTP会自动解码分块内容,不需要额外处理。如果是更低版本,可能需要手动处理,但现在应该很少用到了。
内容的提问来源于stack exchange,提问作者Anish Gopinath
相关产品推荐
相关产品推荐

