WebObjects/Web 服务/问题
本节描述使用WebObjects Web 服务时有时会遇到的一些问题和错误。
- 作者: Francis Labrie
- 受影响的产品: WebObjects 5.2.x、5.3.x
- 错误引用: rdar://3546304
DirectToWebService 定义的 Web 服务不会返回正确的 WSDL 文档,即使遵循了正确的过程(请参见安全 Web 服务)。因此,只有使用 com.webobjects.appserver.WOWebServiceRegistrar
类手动注册的类面向的 Web 服务才能生成正确的 WSDL。
来自 Apple 的 Darel Lee 告诉我,现在,动态 WSDL 生成对开发者不可用,因此目前没有干净的解决方案来执行此操作。一种解决方法是为要使用安全 HTTPS 引用进行操作的每个操作,使用 serviceLocationURL
键硬编码规则(com.webobjects.directtoweb.Assignment
类型)。例如
((operationName="anOperation") and (serviceName="Service")) -> serviceLocationURL="https://host.net/cgi-bin/Service.woa/ws/Service"
如果您需要所有操作都使用安全协议进行调用,您也可以定义如下更通用的规则
(serviceName="Service") -> serviceLocationURL="https://host.net/cgi-bin/Service.woa/ws/Service"
- 作者: Francis Labrie
- 受影响的产品: WebObjects 5.2.x、5.3.x
- 错误引用: rdar://3546330
使用 com.webobjects.appserver.WOWebServiceRegistrar
类向 Web 服务注册的自定义 SOAP 序列化器和反序列化器从未添加到 WSDL 的类型/架构定义中。显示的唯一类型定义如下
<types> <schema targetNamespace="http://lang.java/" xmlns:soapenc= "http://schemas.xmlsoap.org/soap/encoding/" xmlns= "http://www.w3.org/2001/XMLSchema"> <complexType name="Class"> <sequence/> </complexType> <complexType name="ArrayOf_xsd_any"> <complexContent> <restriction base="soapenc:Array"> <attribute ref="soapenc:arrayType" wsdl:arrayType= "xsd:any[]"/> </restriction> </complexContent> </complexType> <element name="ArrayOf_xsd_any" nillable="true" type= "lang:ArrayOf_xsd_any"/> </schema> <schema targetNamespace="http://www.apple.com/webobjects/ webservices/soap/" xmlns:soapenc="http://schemas.xmlsoap.org/ soap/encoding/" xmlns="http://www.w3.org/2001/XMLSchema"> <complexType name="EOGlobalID"> <element name="entityName" type="xsd:string"/> <element name="primaryKeys" type="lang:ArrayOf_xsd_any"/> </complexType> <element name="EOGlobalID" type="tns:EOGlobalID"/> <complexType name="EOEnterpriseObject"> <element name="entityName" type="xsd:string"/> <element name="globalID" type="webobjects:EOGlobalID"/> <element name="properties" type="soapenc:Struct"/> </complexType> </schema> </types>
我现在不知道任何动态解决方法... 但是可以将静态完整 WSDL 通过直接操作共享。不过不太方便...
- 作者: Francis Labrie
- 受影响的产品: WebObjects 5.2.x、5.3.x
- 错误引用
DirectToWebService 定义的 Web 服务无法返回具有自定义命名空间和定义名称属性值的 WSDL。更糟糕的是,生成的命名空间甚至可能包含 WebObjects 应用程序实例编号或错误的主机名。
根据 Darel Lee 的提示,我在 com.webobjects.webservices.generation._private.WOWSDLTemplate
类中发现了一些从 user.d2wmodel DirectToWebService 规则文件中读取的额外键定义。例如
- serviceLocationURL:一个允许设置操作的定位 URL 的键。如果您需要使用安全 HTTPS 引用来访问您的 Web 服务,这将非常有用;
- WSDLDefinitionName:一个允许更改定义名称的键。因此,您可以设置此值,而不是使用“ServiceNameDefinition”;
- WSDLTargetNamespace:一个允许更改命名空间的键。这最有用了:您可以避免使用 WebObjects HTTP 适配器?的动态生成。
以下是以更改上述值的规则定义示例
(serviceName="Service") -> WSDLTargetNamespace="https://host.net/cgi-bin/Service.woa/ws/Service" (serviceName="Service") -> WSDLDefinitionName="AnotherDefinition" ((operationName="anOperation") and (serviceName="Service")) -> serviceLocationURL="https://host.net/cgi-bin/Service.woa/ws/Service"
- 作者: Francis Labrie
- 受影响的产品: WebObjects 5.2.x、5.3.x
- 错误引用: rdar://3568441
com.webobjects.webservices.client.WOWebServiceClient
类无法连接到需要基本 HTTP 身份验证的服务器,尽管该类提供了注册安全委托的方法(请参见 setSecurityDelegateForServiceNamed(Object, String)
实例方法)。
通常,processClientRequest(MessageContext)
委托方法(请参见 com.webobjects.webservices.support.WOSecurityDelegate
接口文档)将提供一种简单的方法来将用户名和密码设置为消息上下文。但是,类设计存在问题:要注册安全委托,WOWebServiceClient
类必须获取 Web 服务定义语言 (WSDL) XML 文档。但是要访问此 WSDL,必须设置身份验证标头。这就是典型的先有鸡还是先有蛋的问题...
最好的做法是在 `WOWebServiceClient` 类中添加一个默认方法,在类获取 WSDL 之前注册一个与服务名称无关的默认安全代理。但不幸的是,所有允许这种行为变化的关键方法都是私有的,所以子类化不是解决方案......
但是仍然可以采用一种变通方法
- 使用 `java.net.URL` 实例自行获取 WSDL 文档并将其存储到本地文件系统,并设置 `java.net.URLConnection` 的基本 HTTP 身份验证标头字段;
- 实例化另一个引用本地 WSDL 文档文件的 `java.net.URL` 类;
- 使用文件 URL 实例化 `com.webobjects.webservices.client.WOWebServiceClient` 类;
- 为每个服务设置一个安全代理,该代理将为基本 HTTP 身份验证添加适当的凭据信息。
就是这样。看起来像一个很大的黑客,但它确实有效......
- 作者: Francis Labrie
- 受影响的产品: WebObjects 5.2.x、5.3.x
- Bug 引用: rdar://4196417
HTTPS 协议引用可以在 Web 服务 WSDL 中发布。但不幸的是,WebObjects 似乎忽略了除默认 443 之外的其他端口。
这个问题与 `com.webobjects.appserver.WORequest` 构建 URL 前缀的方式有关:如果协议是安全的并且在调用 `_completeURLPrefix(StringBuffer,boolean,int)` 方法时未设置端口(即 0),则端口将始终为 443。不幸的是,Web 服务 `com.webobjects.appserver._private.WOWebService` 类似乎在没有设置端口号的情况下调用了此方法。
要解决此错误,您可以像这样对 `com.webobjects.appserver.WORequest` 类进行子类化
package com.smoguli.appserver; import com.webobjects.appserver.WORequest; import com.webobjects.foundation.NSData; import com.webobjects.foundation.NSDictionary; /** * This class provide fixed {@link com.webobjects.appserver.WORequest} methods. * To use it, just overload the {@link com.webobjects.appserver.WOApplication. * createRequest(String,String,String,NSDictionary,NSData,NSDictionary)} method * to instanciate this class instead. * * @author Francis Labrie <francis.labrie at smoguli.com> */ public class WOFixedRequest extends WORequest { /** * @see com.webobjects.appserver.WORequest#WORequest(String,String,String, * NSDictionary,NSData,NSDictionary) */ public WOFixedRequest(String method, String url, String httpVersion, NSDictionary headers, NSData content, NSDictionary info) { super(method, url, httpVersion, headers, content, info); } // WOFixedRequest /** * This method builds the URL prefix into the <code>urlPrefix</code> buffer * with the appropriate protocol (<code>http</code> or <code>https</code>) * and the right TCP port. But unlike the {@link com.webobjects.appserver. * WORequest#_completeURLPrefix(StringBuffer,boolean,int} method, it * supports secure HTTP protocol (<code>https</code>) with port other than * <code>443</code>, even if the <code>port</code> parameter is set * <code>0</code>. * * @param urlPrefix the buffer that receives the contructed URL. * @param isSecure a flag indicating if the protocol is secure. * @param port the port number. */ public void _completeURLPrefix(StringBuffer urlPrefix, boolean isSecure, int port) { if(isSecure && (port == 0)) { String serverPort; serverPort = _serverPort(); if((serverPort != null) && !serverPort.equals("443")) { try { port = Integer.parseInt(serverPort); } catch(NumberFormatException exception) {} // catch } // if } // if super._completeURLPrefix(urlPrefix, isSecure, port); } // _completeURLPrefix } // WOFixedRequest