2

CORS と WCF (REST ではなく SOAP) の統合に問題があります。js からリクエストを行うと、WCF トレース ログに「The body of the message cannot be read because it is empty」という例外が表示されます (論理的には、OPTION CORS リクエストに関連して)。

体:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:a="http://www.w3.org/2005/08/addressing/">
    <s:Header>
    </s:Header>
    <s:Body>
        <GetInfo xmlns="http://tempuri.org/"></GetInfo>
    </s:Body>
</s:Envelope>

JS リクエスト:

$.ajax({
   type: "POST",
   url: "http://localhost:8081/service_deploy/service1.svc/serviceSoap",    
   headers: { "SOAPAction": "http://tempuri.org/IService/GetInfo" },
   data: body,      
   contentType: "text/xml",   
   timeout: 10000
});

CORS リクエスト:

OPTIONS http://localhost:8081/service_deploy/service1.svc/serviceSoap
HTTP/1.1
Host: localhost:8081
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:16.0) Gecko/20100101 Firefox/16.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive
Origin: http://localhost:49209
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type,soapaction
Pragma: no-cache
Cache-Control: no-cache

例外:

Type: System.ServiceModel.ProtocolException, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Mes: There is a problem with the XML that was received from the network. See inner exception for more details.
  Inner type: System.Xml.XmlException, System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
  Inner mes: The body of the message cannot be read because it is empty.

スタックトレース:

System.ServiceModel.Channels.HttpChannelListener.HttpContextReceived(HttpRequestContext context, Action callback)    System.ServiceModel.Activation.HostedHttpTransportManager.HttpContextReceived(HostedHttpRequestAsyncResult result)
System.ServiceModel.Activation.HostedHttpRequestAsyncResult.HandleRequest()
System.ServiceModel.Activation.HostedHttpRequestAsyncResult.BeginRequest()
System.ServiceModel.Activation.HostedHttpRequestAsyncResult.OnBeginRequest(Object state)
System.ServiceModel.AspNetPartialTrustHelpers.PartialTrustInvoke(ContextCallback callback, Object state)
System.ServiceModel.Activation.HostedHttpRequestAsyncResult.OnBeginRequestWithFlow(Object state)
System.Runtime.IOThreadScheduler.ScheduledOverlapped.IOCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* nativeOverlapped)
System.Runtime.Fx.IOCompletionThunk.UnhandledExceptionFrame(UInt32 error, UInt32 bytesRead, NativeOverlapped* nativeOverlapped)
System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)

CORS と WCF SOAP を統合したり、この低レベルの WCF 例外を処理するにはどうすればよいですか?

4

1 に答える 1

1

サーブレットコンテナには、適切なヘッダーが設定されたOPTIONSリクエストとアンサーを処理するフィルタが必要です。

ファイルweb.xmlは次のようになります

[...]
<filter>
   <filter-name>CORSFilter</filter-name>
   <filter-class>my.namespace.CORSFilter</filter-class>
 </filter>
 <filter-mapping>
   <filter-name>CORSFilter</filter-name>
   <url-pattern>/*</url-pattern>
 </filter-mapping>
[...]

そしてこれはCORSフィルターの例です

public class CORSFilter implements Filter {
  // For security reasons set this regex to an appropriate value
  // example: ".*example\\.com"
  private static final String ALLOWED_DOMAINS_REGEXP = ".*";

  public void doFilter(ServletRequest servletRequest,
      ServletResponse servletResponse, FilterChain filterChain)
      throws IOException, ServletException {

    HttpServletRequest req = (HttpServletRequest) servletRequest;
    HttpServletResponse resp = (HttpServletResponse) servletResponse;

    String origin = req.getHeader("Origin");
    if (origin != null && origin.matches(ALLOWED_DOMAINS_REGEXP)) {
      resp.addHeader("Access-Control-Allow-Origin", origin);
      if ("options".equalsIgnoreCase(req.getMethod())) {
        resp.setHeader("Allow", "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS");
        if (origin != null) {
          String headers = req.getHeader("Access-Control-Request-Headers");
          String method = req.getHeader("Access-Control-Request-Method");
          resp.addHeader("Access-Control-Allow-Methods", method);
          resp.addHeader("Access-Control-Allow-Headers", headers);
          resp.setContentType("text/plain");
        }
        resp.getWriter().flush();
        return;
      }
    }

    // Fix the ios6 issue: caching post requests
    if ("post".equalsIgnoreCase(req.getMethod())) {
      resp.addHeader("Cache-Control", "no-cache");
    }

    if (filterChain != null) {
      filterChain.doFilter(req, resp);
    }
  }

  @Override public void destroy() {}
  @Override public void init(FilterConfig arg0) throws ServletException {}
}
于 2012-12-23T13:55:24.910 に答える