21

我试图允许来自托管在 localhost:80 上的 javascript 应用程序的 POST 请求到托管在不同端口的 WCF RESTful 服务,但不知何故它不起作用。我尝试将自定义属性添加到标头,并以编程方式将其添加到我的服务JSONData方法中,但我的响应中仍然出现“405 Method not allowed”。这里的正确方法是什么?

这是我的界面:

namespace RestService
{
    public class RestServiceImpl : IRestServiceImpl
    {
        #region IRestServiceImpl Members

        public string JSONData()
        {
            HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
            return "Your POST request";
        }

        #endregion
    }
}

和服务代码:

using System.ServiceModel;
using System.ServiceModel.Web;
using System.Web.Script.Services;

namespace RestService
{

    [ServiceContract]
    public interface IRestServiceImpl
    {
        [OperationContract]
        [ScriptMethod]
        [WebInvoke(Method = "POST",
            ResponseFormat = WebMessageFormat.Json,
            BodyStyle = WebMessageBodyStyle.Bare,
            UriTemplate = "export")]
        string JSONData();
    }
}

最后是配置:

<?xml version="1.0"?>
<configuration>

  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
  <system.serviceModel>
    <services>
      <service name="RestService.RestServiceImpl" behaviorConfiguration="ServiceBehaviour">
        <endpoint address ="" binding="webHttpBinding" contract="RestService.IRestServiceImpl" behaviorConfiguration="web">
        </endpoint>
      </service>
    </services>

    <behaviors>
      <serviceBehaviors>
        <behavior name="ServiceBehaviour">
          <serviceMetadata httpGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>
      <endpointBehaviors>
        <behavior name="web">
          <webHttp/>
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
    <httpProtocol>
      <customHeaders>
         <add name="Access-Control-Allow-Origin" value="*" />
      </customHeaders>
</httpProtocol>  
  </system.webServer>

</configuration>
4

5 回答 5

34

这对我来说比 Web.config 版本更好:

创建一个Global.asax

将此方法添加到Global.asax.cs

using System.Web;

namespace StackOverflow
{
    public class Global : System.Web.HttpApplication
    {
        protected void Application_BeginRequest(object sender, EventArgs e)
        {
            HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
            if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
            {
                HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST");
                HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
                HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
                HttpContext.Current.Response.End();
            }
        }
    }
}

参考: http: //www.dotnet-tricks.com/Tutorial/wcf/X8QN260412-Calling-Cross-Domain-WCF-Service-using-Jquery.html

于 2014-09-25T13:46:03.800 回答
17

将这些节点添加到您的 Web.config:

<configuration>
  <system.webServer>
    <httpProtocol>
      <customHeaders>
        <add name="Access-Control-Allow-Origin" value="*"/>
        <add name="Access-Control-Allow-Headers" value="Content-Type, Accept" />
        <add name="Access-Control-Allow-Methods" value="POST,GET,OPTIONS" />
        <add name="Access-Control-Max-Age" value="1728000" />
      </customHeaders>
    </httpProtocol>
  </system.webServer>
</configuration>

参考:http ://theagilecoder.wordpress.com/2014/07/07/wcf-and-cors-no-access-control-allow-origin-header-is-present-on-the-requested-resource/

于 2014-09-18T14:25:44.957 回答
9

为非 GET 请求启用 CORS 不仅需要设置Access-Control-Allow-Origin标头 - 它还需要处理预检请求,这些OPTIONS请求会询问服务器是否可以安全地执行可能更改数据的操作(例如,POST、PUT、DELETE ) 在发送实际请求之前。

我写了一篇关于为 WCF 添加 CORS 支持的博客文章。这不是最简单的实现,但希望帖子中的代码可以简单地复制/粘贴到您的项目中。该帖子可在http://blogs.msdn.com/b/carlosfigueira/archive/2012/05/15/implementing-cors-support-in-wcf.aspx找到。

于 2012-12-27T03:12:32.643 回答
0

下面的 .NET 代码 (global.asax) 有一个重要的区别,即代替 *,回显 Origin 域可能会更好,因为这可以通过 CORS(例如 NTLM / Kerberos)以及 Preflight 进行身份验证。

void Application_BeginRequest(object sender, EventArgs e)
{
    if (Request.HttpMethod == "OPTIONS")
    {
        Response.AddHeader("Access-Control-Allow-Methods", "GET, POST");
        Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
        Response.AddHeader("Access-Control-Max-Age", "1728000");
        Response.End();
    }
    else
    {
        Response.AddHeader("Access-Control-Allow-Credentials", "true");

        if (Request.Headers["Origin"] != null)
            Response.AddHeader("Access-Control-Allow-Origin" , Request.Headers["Origin"]);
        else
            Response.AddHeader("Access-Control-Allow-Origin" , "*");
    }
}
于 2017-12-21T02:16:31.933 回答
0

上述所有解决方案都修改了 CORS 响应,以允许使用 * 属性启用所有站点的 CORS。这对我来说似乎是一个安全风险,因为我想控制哪些站点可以访问我的 REST 服务。我希望这可以帮助其他人解决相同类型的问题。

我首先通过使用允许将字符串数组存储在 MySettings 中的 SpecializedString 集合来修改 web.config 文件以包含我允许的源站点。该代码位于 VB.Net 中,因此如果需要,应该可以轻松移植到 c#。

<applicationSettings>
    <YourService.My.MySettings>
        <setting name="AllowedOrigins" serializeAs="Xml">
            <value>
                <ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xmlns:xsd="http://www.w3.org/2001/XMLSchema">
                    <string>http://localhost:62087</string>
                    <string>https://yourallowedorign2:3344</string>
                </ArrayOfString>
            </value>
        </setting>
    </YourService.My.MySettings>
</applicationSettings>

并且在 Global.asax.vb 文件中,我对 Application_BeginRequest 代码做了如下调整。

注意获取 Allowed Origins 的支持函数

Private allowedOrigins As String()

Public Function GetAllowedOrigins() As String()
    Dim mySetting As StringCollection = My.Settings.AllowedOrigins

    If mySetting IsNot Nothing Then
        ' If you're using .NET 3.5 or greater:
        Return mySetting.Cast(Of String)().ToArray()

        ' Otherwise:
        Dim array(mySetting.Count - 1) As String
        mySetting.CopyTo(array, 0)

        Return array
    Else
        Dim strEmpty() As String = Enumerable.Empty(Of String).ToArray
        Return strEmpty
    End If
End Function

Sub Application_BeginRequest(ByVal sender As Object, ByVal e As EventArgs)
    ' Fires at the beginning of each request
    Dim origin As String = sender.Request.Headers("Origin")
    If origin IsNot Nothing Then
        Dim originURI As Uri = New Uri(origin)
        Dim requestHost As String = originURI.Scheme + Uri.SchemeDelimiter + originURI.Host
        If originURI.Port <> 80 Then
            requestHost += ":" + originURI.Port.ToString
        End If

        If allowedOrigins Is Nothing Then
            allowedOrigins = GetAllowedOrigins()
        End If
        If allowedOrigins IsNot Nothing AndAlso allowedOrigins.Contains(requestHost) Then
            HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", requestHost)
            If HttpContext.Current.Request.HttpMethod = "OPTIONS" Then
                HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE")
                HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With")
                HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000")
                HttpContext.Current.Response.End()
            End If
        End If
    End If

End Sub

我发现的另一个警告是我需要在 Access-Control-Allow-Headers 标头中添加 X-Requested-With 值。如果您收到 CORS 错误,请先检查该标头以查看是否需要其他选项。

我希望这有助于其他可能对这个太常见的问题感到沮丧的人。

于 2021-03-08T21:43:07.347 回答