允许浏览器从Windows服务托管的WCF服务请求JSONP

时间:2016-11-03 22:59:05

标签: jquery wcf cors jsonp same-origin-policy

我正在尝试安装托管的Windows服务托管的WCF服务,该服务可以为我的网页提供有关安装它的计算机的一些信息。我的想法是,我页面的所有访问者都将安装此服务,页面可以使用javascript调用localhost服务来获取数据。

我们的一位开发人员通过为服务启用CORS来实现这一点 CarlosFigueira's example here。除了在Edge中,它在所有浏览器中都很好用,它会出现错误SCRIPT7002: XMLHttpRequest: Network Error 0x2efd。我想不出任何理由,也找不到任何关于它的信息,所以我想也许我应该尝试一种jsonp方法。

我认为jsonp应该绕过同源策略,但我只能通过上面提供的支持CORS的WCF服务来实现它。只要我删除它并只使用常规ServiceHost,我就会开始收到400条错误的请求响应。

**“工作”是指浏览器成功发出请求并收到响应。但是,响应是普通的json,而不是jsonp。我读到WCF 4.5应该自动识别“回调”参数并将json包装在“P”中,但这似乎并没有发生。我认为这是一个无关的次要问题。

但主要的问题是,我认为jsonp应该是一种提出跨域请求的方式,那么为什么我必须在我的WCF服务上启用所有CORS头文件以使其工作?

Windows Service OnStart:

CorsEnabledServiceHostFactory serviceHostFactory = new CorsEnabledServiceHostFactory();
serviceHost = serviceHostFactory.GetServiceHost(typeof(LPA.MachineDataService), baseAddresses);  //Works

//LPA.MachineDataService singleton = new LPA.MachineDataService();
//serviceHost = new System.ServiceModel.ServiceHost(singleton, baseAddresses);  //Doesn't work

serviceHost.Open();

ServiceContract:

[ServiceContract]
public interface IMachineDataService
{
    [WebGet(UriTemplate = "GetValues", ResponseFormat=WebMessageFormat.Json)]
    LPA.MachineData GetValues();
}

服务实施:

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class MachineDataService : IMachineDataService
{
    public LPA.MachineData GetValues()
    {
        LPA.MachineData result = null;

        try
        {
            WebOperationContext.Current.OutgoingResponse.Headers[HttpResponseHeader.CacheControl] = "no-cache";

            result = PcValues.GetValues();
        }
        catch (Exception ex)
        {
        }

        return result;
    }
}

来自Windows服务app.config:

<system.serviceModel>
<behaviors>
  <serviceBehaviors>
    <behavior name="">
      <serviceMetadata httpGetEnabled="true" />
      <serviceDebug includeExceptionDetailInFaults="false" />
    </behavior>
  </serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true" />
<standardEndpoints>
  <webScriptEndpoint>
    <standardEndpoint crossDomainScriptAccessEnabled="true" name=""></standardEndpoint>
  </webScriptEndpoint>
  <webHttpEndpoint>
    <standardEndpoint crossDomainScriptAccessEnabled="true" name=""></standardEndpoint>
  </webHttpEndpoint>
</standardEndpoints>

</system.serviceModel>

jQuery Call:

var valuesAddress = "http://localhost:56731/ValuesService/GetValues";

$.ajax({
    type: "GET",
    url: valuesAddress,
    dataType: "jsonp",
    success: function (result) {
        $("[data-authinfo]").val(result);
    },
    error: function (xhr, status, code) {

    }
});

1 个答案:

答案 0 :(得分:0)

我从头开始自我托管的虚拟服务,并将问题缩小到我的配置。它需要使用webHttpBinding作为REST服务,我想,没有明确指定,它使用的是basicHttpBinding。我删除了标准端点并自己配置了端点:

<system.serviceModel>
  <behaviors>
    <endpointBehaviors>
      <behavior name="webHttpBehavior">
        <webHttp/>
      </behavior>
    </endpointBehaviors>
  </behaviors>
  <bindings>
    <webHttpBinding>
      <binding name="webHttpBinding" crossDomainScriptAccessEnabled="true" />
    </webHttpBinding>
  </bindings>
  <services>
    <service name="LessonPlansAuthentication.MachineDataService">
      <endpoint address="" binding="webHttpBinding"
                bindingConfiguration="webHttpBinding"
                behaviorConfiguration="webHttpBehavior"
                contract="LessonPlansAuthentication.IMachineDataService"/>
    </service>
  </services>
  <serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true" />
</system.serviceModel>

如果我在进行此更改之前尝试访问浏览器中的URL,则只会显示一个空白页面。之后,它实际上返回JSON数据,jQuery可以成功地对URL进行JSONP AJAX调用。

我还不清楚使用webHttp绑定&amp;端点以及crossDomainScriptAccessEnabled=true实际上已更改以允许呼叫。响应的内容类型可能?对此有任何意见将不胜感激。

现在我只需验证它适用于所有浏览器。如果有人知道为什么Edge不支持启用CORS的服务,请发表评论。