Статьи

Перезапись пространства имен Mule WS Proxy

Сегодня я видел две вещи, которые я не могу вспомнить, видел раньше:

Первым был WSDL для веб-службы, в которой целевое пространство имен и адрес службы были идентичны. Насколько я знаю, это ничто не мешает, это только своеобразно — по крайней мере, для меня.

Во-вторых, когда я помещал прокси-сервер веб-службы Mule перед веб-службой, раскрывая WSDL, упомянутый выше, был переписан не только адрес порта конечной точки веб-службы, но и целевое пространство имен.
Если бы я ожидал, что вы поверите на мое слово, тогда этот пост закончится здесь. Тем не менее, я не ожидаю, что вы поверите моему слову, и я хотел изучить это поведение более внимательно.

Прежде чем мы рассмотрим некоторые убедительные доказательства, я просто хочу упомянуть, что я использовал Mule CE 3.4.0 при реализации примера программы в этом посте.

Препараты

В вашей любимой интегрированной среде разработки на основе Eclipse с установленным плагином MuleStudio создайте проект Mule. В этом проекте Mule создайте два потока Mule; один с именем «helloserviceflow» и другой с именем «wsproxybug».
В потоке «helloserviceflow» вставьте следующую конфигурацию потока Mule:

<?xml version="1.0" encoding="UTF-8"?>
<mule
    xmlns:cxf="http://www.mulesoft.org/schema/mule/cxf"
    xmlns="http://www.mulesoft.org/schema/mule/core"
    xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"
    xmlns:spring="http://www.springframework.org/schema/beans"
    xmlns:test="http://www.mulesoft.org/schema/mule/test"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
http://www.mulesoft.org/schema/mule/cxf http://www.mulesoft.org/schema/mule/cxf/current/mule-cxf.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-current.xsd
http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/test http://www.mulesoft.org/schema/mule/test/current/mule-test.xsd">

    <spring:beans>
        <spring:bean id="helloService" class="se.ivankrizsan.mule.wsproxybug.HelloService"/>
    </spring:beans>

    <flow name="HelloServiceFlow">
        <inbound-endpoint
            address="http://localhost:8182/services/GreetingService"
            exchange-pattern="request-response"/>
        <cxf:jaxws-service serviceClass="se.ivankrizsan.mule.wsproxybug.HelloService"/>
        <component>
            <spring-object bean="helloService"/>
        </component>
    </flow>
</mule>

Создайте Java-класс, который реализует HelloService:

package se.ivankrizsan.mule.wsproxybug;

import java.util.Date;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;

/**
* SOAP web service endpoint implementation class that implements a service that extends greetings.
* 
* @author Ivan Krizsan
*/
@WebService(targetNamespace = "http://localhost:8182/services/GreetingService")
public class HelloService {
    /**
    * Greets the person with the supplied name.
    * 
    * @param inName Name of person to greet.
    * @return Greeting.
    */
    @WebResult(name = "greeting")
    public String greet(@WebParam(name = "inName") final String inName) {
        return "Hello " + inName + ", the time is now " + new Date();
    }
}

Обратите внимание, что в аннотации @WebService я указал целевое пространство имен веб-службы для URL-адреса, который идентичен адресу входящей конечной точки в HelloServiceFlow.

Заключительная часть подготовки состоит в установке дополнения HttpRequester в Mozilla Firefox. Это дополнение позволяет отправлять различные виды HTTP-запросов (GET, POST, PUT и т. Д.) И анализировать результаты из Firefox.

Прокси Вебсервис

В потоке «wsproxybug» вставьте следующую конфигурацию Mule:

<?xml version="1.0" encoding="UTF-8"?>
<mule
    xmlns:http="http://www.mulesoft.org/schema/mule/http"
    xmlns:pattern="http://www.mulesoft.org/schema/mule/pattern"
    xmlns="http://www.mulesoft.org/schema/mule/core"
    xmlns:spring="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    version="CE-3.4.0"
    xsi:schemaLocation="
http://www.mulesoft.org/schema/mule/http
http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd 

http://www.mulesoft.org/schema/mule/pattern
http://www.mulesoft.org/schema/mule/pattern/current/mule-pattern.xsd

http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-current.xsd

http://www.mulesoft.org/schema/mule/core
http://www.mulesoft.org/schema/mule/core/current/mule.xsd">

    <pattern:web-service-proxy name="WSProxyBugFlow">
        <http:inbound-endpoint address="http://localhost:8190/proxiedservices/GreetingService" />
        <http:outbound-endpoint address="http://localhost:8182/services/GreetingService" />
    </pattern:web-service-proxy>
</mule>

Для новичков в шаблоне прокси веб-службы Mule, я просто хочу упомянуть, что этот шаблон очень упрощает прокси веб-службы, выставляя ее по URL-адресу, указанному во входящей конечной точке. URL-адрес веб-службы, которая должна быть прокси, указана в исходящей конечной точке, которую проницательный читатель заметит, совпадает с URL-адресом HelloService, который был частью подготовки.

Запустите пример программы

Теперь мы готовы запустить пример программы. Щелкните правой кнопкой мыши проект Mule в Eclipse и выберите «Запуск от имени» -> «Mule Application».
Через некоторое время в консоли должен появиться вывод о том, что приложение Mule было успешно запущено.

Изучите HelloService

В качестве первого шага мы рассмотрим HelloService, чтобы узнать, какие данные он представляет о себе:
в Firefox откройте дополнение HttpRequester и вставьте URL-адрес http: // localhost: 8182 / services / GreetingService? Wsdl в верхний левая часть диалога. Затем нажмите кнопку GET (третий слева под полем URL). Результат должен выглядеть так:

Используя HttpRequester, мы можем видеть, среди прочего, что:

  • Выполнение запроса заняло 47 мс.
    Это в моей среде — время может варьироваться в зависимости от вашей среды.
  • Тип содержимого ответа «text / xml».
  • Пространство имен в WSDL такое же, как мы указали в аннотации @WebService в классе HelloService ранее:
<?xml version='1.0' encoding='UTF-8'?>
<wsdl:definitions
 name="HelloServiceService"
 targetNamespace="http://localhost:8182/services/GreetingService"
 xmlns:ns1="http://schemas.xmlsoap.org/soap/http"
 xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
 xmlns:tns="http://localhost:8182/services/GreetingService"
 xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
 xmlns:xsd="http://www.w3.org/2001/XMLSchema">

Порт службы, где указан адрес конечной точки службы, выглядит следующим образом:

<wsdl:port binding="tns:HelloServiceServiceSoapBinding" name="HelloServicePort">
 <soap:address location="http://localhost:8182/services/GreetingService"/>
</wsdl:port>

Проверьте сервисный прокси

Давайте посмотрим на прокси-версию HelloService.
Повторите упражнение по отправке GET-запроса на WSDL в HttpRequester, но на этот раз используйте этот URL: http: // localhost: 8190 / proxiedservices / GreetingService? Wsdl
Результат должен выглядеть примерно так:

Изучив результат более внимательно, мы видим, что:

  • Для выполнения запроса через прокси потребовалось более трех раз.
    В моем случае 175 мс через прокси по сравнению с 47 мс прямого доступа. Возможно, было бы более просто сказать, что прокси добавил к запросу около 125 мс.
  • Тип содержимого ответа, возвращаемого прокси-сервером, — «text / plain».
  • Целевое пространство имен WSDL изменилось:
    «Компьютер» — это имя моего компьютера, и прокси-сервер, по-видимому, заменил «localhost» на разрешенное имя адреса моего компьютера.
    Это было не совсем ожидаемое поведение прокси.
<?xml version='1.0' encoding='UTF-8'?>
<wsdl:definitions
 name="HelloServiceService" 
 targetNamespace="http://Computer:8190/proxiedservices/GreetingService"
 xmlns:ns1="http://schemas.xmlsoap.org/soap/http"
 xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
 xmlns:tns="http://Computer:8190/proxiedservices/GreetingService"
 xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
 xmlns:xsd="http://www.w3.org/2001/XMLSchema">

Порт службы выглядит следующим образом:
прокси сделал эту часть хорошо.

<wsdl:port binding="tns:HelloServiceServiceSoapBinding" name="HelloServicePort">
   <soap:address location="http://Computer:8190/proxiedservices/GreetingService"/>
</wsdl:port>

Класс Mule WSProxy

Прокси-сервер веб-службы в Mule реализуется классом org.mule.module.ws.construct.WSProxy , который, в свою очередь, содержит ряд внутренних классов. Один из внутренних классов содержит метод с именем modifyServiceAddress , который отвечает за переписывание адреса службы в WSDL. К сожалению, он использует метод replaceAll в классе String, что приводит к поведению, которое мы видели.
Что еще более прискорбно, так это дизайн класса WSProxy с закрытыми внутренними классами, который, хотя есть конструктор, принимающий экземпляр AbstractProxyRequestProcessor в качестве параметра, я не могу понять, как создать подкласс, который находится за пределами WSProxyкласс класса AbstractProxyRequestProcessor .

Альтернативы?

Ну есть ли альтернативы?
Конечно, вы можете реализовать что-то свое, используя Mule, пока вы ждете исправления этой проблемы: https://www.mulesoft.org/jira/browse/MULE-7466
Как насчет альтернатив не-Mule?
Я не буду обсуждать различные реализации чистого HTTP-прокси, поскольку они не смогут переписывать адреса служб в WSDL. Однако, возможно, стоит спросить себя, действительно ли вам нужен прокси-сервер веб-службы, способный перезаписывать адреса служб в WSDL.

Итак, давайте предположим, что у вас должен быть прокси-сервер веб-службы, способный перезаписывать адреса служб. Что делать?

Apache Camel

Если альтернативы, которые не используют Mule, могут быть рассмотрены, то Apache Camel определенно является кандидатом. Есть даже пример, который реализует прокси веб-службы. В дистрибутиве 2.13.0 он находится в каталоге «camel-example-cxf-proxy» в каталоге «examples».

Я позволил себе немного изменить пример прокси. Прежде всего, я хотел чистого прокси без каких-либо изменений в запросах. Во-вторых, я адаптировал прокси для HelloService. Результат выглядит так:

<?xml version="1.0" encoding="UTF-8"?>
<!--
    Licensed to the Apache Software Foundation (ASF) under one or more
    contributor license agreements.  See the NOTICE file distributed with
    this work for additional information regarding copyright ownership.
    The ASF licenses this file to You under the Apache License, Version 2.0
    (the "License"); you may not use this file except in compliance with
    the License.  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
-->
<beans
    xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:camel="http://camel.apache.org/schema/spring"
    xmlns:cxf="http://camel.apache.org/schema/cxf"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       
       http://camel.apache.org/schema/spring
       http://camel.apache.org/schema/spring/camel-spring.xsd
       
       http://camel.apache.org/schema/cxf
       http://camel.apache.org/schema/cxf/camel-cxf.xsd">

    <!--
        Endpoint of the web service proxy which:
        Has the address specified by the address attribute.
        Exposes the port specified by the endpointName attribute in the
        service specified by the serviceName attribute from the WSDL
        specified by the wsdlURL attribute.
        
        Note how the namespace of the WSDL is specified and its namespace
        prefix is used in the port and service names.
    -->
    <cxf:cxfEndpoint id="proxyFrontEnd"
        address="http://localhost:8290/proxiedservices/GreetingService"
        endpointName="gs:HelloServicePort"
        serviceName="gs:HelloServiceService"
        wsdlURL="http://localhost:8182/services/GreetingService?wsdl"
        xmlns:gs="http://localhost:8182/services/GreetingService" />

    <!--
        Apache Camel route that proxies a web service and logs requests
        and responses to the proxy.
    -->
    <camelContext xmlns="http://camel.apache.org/schema/spring">

        <endpoint id="callRealWebService" uri="http://localhost:8182/services/GreetingService" />

        <route>
            <from uri="cxf:bean:proxyFrontEnd?dataFormat=MESSAGE" />
            <!-- Log incoming request. -->
            <to uri="log:input" />
            <!-- Invoke the web service that is being proxied. -->
            <to ref="callRealWebService" />
            <!-- Log outgoing response. -->
            <to uri="log:output" />
        </route>
    </camelContext>
</beans>

Обратите внимание, что при запуске прокси-сервера Apache Camel служба HelloService должна быть запущена.

Так это работает?

Как видно из рисунка выше, он работает. Тип содержимого text / xml, целевое пространство имен WSDL не изменилось, и, как видно из приведенного ниже, адрес конечной точки службы был переписан. Накладные расходы, добавленные прокси Camel, примерно такие же, как у прокси Mule.

<wsdl:port binding="tns:HelloServiceServiceSoapBinding" name="HelloServicePort">
   <soap:address location="http://Computer:8190/proxiedservices/GreetingService"/>
</wsdl:port>

перепонка

Если существует много веб-сервисов, которые должны быть прокси-серверы, и / или конфигурация прокси-серверов веб-сервисов в графическом интерфейсе предпочтительна, то Membrane Service Proxy может быть вариантом.