从Oracle存储过程访问Web服务

是否有人从Oracle存储过程成功访问过Web服务? 如果是这样,它是Java存储过程吗? PL / SQL存储过程?

我有什么理由不尝试从存储过程中访问WS?

这是我到目前为止发现的一些参考文献

  • 数据库Web服务
  • 从Java存储过程调用外部Web服务

..澄清一下,这是针对SOAP调用的

首先,你打电话给什么样的网络服务? 我假设SOAP或REST。

对于REST Web服务,UTL_HTTP通常绰绰有余,在简单的PL / SQL存储过程中结合了一点XPath。

对于SOAP Web服务,它取决于您需要(或想要)的复杂程度。 您当然可以使用XQuery创建符合Web服务规范的XML文档,使用UTL_HTTP发布文档并获取响应,然后使用一些XPath来解析PL / SQL中的所有响应。 这是一个相对手动且相对powershell的解决方案,但如果您正在谈论少数几个Web服务,它涉及最少的基础设施,并且呼叫可以很快被敲打。

如果您希望调用随着时间的推移而发展,或者您希望有许多过程调用大量的Web服务,那么将时间花在像UTL_DBWS这样的东西上可能是有意义的(但这不是什么,但是,你通常会得到在几个小时内工作)。

将UTL_HTTP包装在一个便利函数中相当简单:

FUNCTION post ( p_url IN VARCHAR2, p_data IN CLOB, p_timeout IN BINARY_INTEGER DEFAULT 60 ) RETURN CLOB IS -- v_request utl_http.req; v_response utl_http.resp; v_buffer CLOB; v_chunk VARCHAR2(4000); v_length NUMBER; v_index NUMBER; BEGIN v_index := 1; v_length := nvl(length(p_data), 0); -- configure HTTP utl_http.set_response_error_check(enable => FALSE); utl_http.set_detailed_excp_support(enable => FALSE); utl_http.set_transfer_timeout(p_timeout); -- send request v_request := utl_http.begin_request(p_url, 'POST','HTTP/1.0'); utl_http.set_header(v_request, 'Content-Type', 'text/xml'); utl_http.set_header(v_request, 'Content-Length', v_length); WHILE v_index <= v_length LOOP utl_http.write_text(v_request, substr(p_data, v_index, 4000)); v_index := v_index + 4000; END LOOP; -- check HTTP status code for error IF v_response.status_code <> utl_http.http_ok THEN raise_application_error( cn_http_error, v_response.status_code || ' - ' || v_response.reason_phrase ); END IF; -- get response dbms_lob.createtemporary(v_buffer, FALSE); v_response := utl_http.get_response(v_request); BEGIN LOOP utl_http.read_text(v_response, v_chunk, 4000); dbms_lob.writeappend(v_buffer, length(v_chunk), v_chunk); END LOOP; EXCEPTION WHEN utl_http.end_of_body THEN NULL; END; utl_http.end_response(v_response); RETURN v_buffer; END; 

那么你只需要一些东西来发布一个SOAP信封:

 FUNCTION invoke ( p_url IN VARCHAR2, p_method IN XMLTYPE, p_timeout IN NUMBER := 60 ) RETURN XMLTYPE IS -- calls the given SOAP service cn_procedure_name CONSTANT VARCHAR2(30) := 'invoke'; -- v_envelope XMLTYPE; v_response CLOB; v_fault XMLTYPE; v_sqlerrm VARCHAR2(2000); BEGIN -- wrap method in SOAP envelope SELECT XMLElement( "soap:Envelope", XMLAttributes( 'http://schemas.xmlsoap.org/soap/envelope/' AS "xmlns:soap" ), XMLElement( "soap:Body", p_method ) ) INTO v_envelope FROM dual; -- POST request v_response := post( p_url, '' || chr(10) || v_envelope.getClobVal(), p_timeout ); IF v_response IS NULL THEN RAISE null_response; END IF; -- parse response BEGIN v_envelope := XMLType(v_response); EXCEPTION WHEN OTHERS THEN v_sqlerrm := SQLERRM; RAISE xml_parse_error; END; -- check for a fault v_fault := v_envelope.extract( '/soap:Envelope/soap:Body/soap:Fault', 'xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"' ); IF v_fault IS NOT NULL THEN v_sqlerrm := v_fault.extract('.//faultstring/text()').getStringVal(); RAISE soap_fault; END IF; -- the actual response is the child of the  element RETURN v_envelope.extract( '/soap:Envelope/soap:Body/*[position() = 1]', 'xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"' ); END; 

请注意,我删除了我们的exception处理块,因为它与示例不是特别相关。

有了它,您可以让任何其他过程生成调用服务所需的XML,通过调用传递它,并解析返回值。

我们在9i数据库上开发了这个解决方案,所以我们还没有研究过UTL_DBWS。 但它很棒。