10 Stimmen

Zugriff auf den Webdienst aus einer gespeicherten Oracle-Prozedur

Hat jemand schon einmal erfolgreich von einer Oracle Stored Procedure auf einen Web Service zugegriffen? Wenn ja, war es eine Java Stored Procedure? Eine PL/SQL gespeicherte Prozedur?

Gibt es einen Grund, warum ich nicht versuchen sollte, von einem gespeicherten Prozess aus auf einen WS zuzugreifen?

Hier sind ein paar Referenzen, die ich bisher gefunden habe

Nur zur Klarstellung, dies ist für SOAP-Aufrufe

13voto

Justin Cave Punkte 220606

Zunächst einmal: Welche Art von Webdienst rufen Sie auf? Ich nehme an, entweder SOAP oder REST.

Für REST-Webdienste ist UTL_HTTP oft mehr als ausreichend, kombiniert mit ein wenig XPath in einer einfachen PL/SQL gespeicherten Prozedur.

Bei SOAP-Webdiensten hängt es davon ab, wie anspruchsvoll Sie sein müssen (oder wollen). Sie können sicherlich XQuery verwenden, um ein XML-Dokument zu erstellen, das den Spezifikationen für den Webdienst entspricht, UTL_HTTP verwenden, um das Dokument zu versenden und die Antwort zu erhalten, und dann XPath verwenden, um die Antwort in PL/SQL zu parsen. Dies ist eine relativ manuelle und relativ brutale Lösung, aber wenn es sich um eine Handvoll Webdienste handelt, ist nur ein Minimum an Infrastruktur erforderlich, und die Aufrufe können ziemlich schnell erstellt werden.

Wenn Sie davon ausgehen, dass sich die Aufrufe im Laufe der Zeit weiterentwickeln oder dass eine Reihe von Prozeduren eine Reihe von Webdiensten aufrufen, ist es wahrscheinlich sinnvoll, Zeit in etwas wie UTL_DBWS zu investieren (das ist allerdings nichts, was man in der Regel in ein paar Stunden zum Laufen bringt).

10voto

kurosch Punkte 2242

Es ist recht einfach, UTL_HTTP in eine Komfortfunktion zu verpacken:

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;

Dann brauchen Sie nur etwas, um einen SOAP-Umschlag zu POSTEN:

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,
        '<?xml version="1.0" encoding="ISO-8859-1"?>' || 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 <soap:Body /> element
    RETURN v_envelope.extract(
        '/soap:Envelope/soap:Body/*[position() = 1]', 
        'xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"'
    );

END;

Beachten Sie, dass ich unseren Block für die Ausnahmebehandlung entfernt habe, da er für das Beispiel nicht besonders relevant ist.

Damit können Sie jede andere Prozedur das XML generieren lassen, das für den Aufruf eines Dienstes erforderlich ist, es über invoke übergeben und den Rückgabewert analysieren.

Wir haben diese Lösung auf einer 9i-Datenbank entwickelt, daher haben wir uns noch nicht mit UTL_DBWS befasst. Sie funktioniert jedoch hervorragend.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X