You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自托管WCF服务配置CORS后仍报预检请求无Access-Control-Allow-Origin头如何解决

问题根因

你遇到的CORS不生效问题由两个核心错误导致:

  1. 浏览器发起跨域请求前会先发送OPTIONS预检请求,WCF默认不会将该类请求路由到你的服务接口,你当前实现的消息拦截器无法触发生效,导致响应没有携带CORS头
  2. 你配置的响应头字段名错误,Access-Control-Request-Method是请求头字段,响应头需要返回Access-Control-Allow-Methods

解决步骤

1. 修正App.config配置

你当前仅配置了basicHttpBinding,但服务实际使用webHttpBinding,需要补充该绑定的跨域配置,同时检查行为扩展配置正确性:

<system.serviceModel>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
    <bindings>
        <!--basicHttpBinding-->
        <basicHttpBinding>
            <binding name="BasicBinding" maxBufferSize="2147483647" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647">
                <readerQuotas maxStringContentLength="2147483647" maxArrayLength="2147483647" />
            </binding>
        </basicHttpBinding>
        <!-- 新增webHttpBinding配置,开启跨域脚本访问 -->
        <webHttpBinding>
            <binding name="corsBinding" crossDomainScriptAccessEnabled="true">
                <security mode="None" />
            </binding>
        </webHttpBinding>
    </bindings>
    <services>
        <!-- endpoint新增bindingConfiguration指定corsBinding -->
        <service name="##.ServiceScanClientService" behaviorConfiguration="serviceBehavior">
            <endpoint address="" binding="webHttpBinding" bindingConfiguration="corsBinding" behaviorConfiguration="jsonBehavior"  contract="##.IServiceScanClientService" />
        </service>      
    </services>
    <extensions>
        <behaviorExtensions>
            <!-- 注意:此处##替换为实际命名空间,程序集名不要带多余空格 -->
            <add name="crossOriginResourceSharingBehavior" type="##.BehaviorAttribute, ServiceScan" />
        </behaviorExtensions>
    </extensions>
    <behaviors>
        <serviceBehaviors>
            <behavior name="serviceBehavior">
            <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
            <serviceDebug includeExceptionDetailInFaults="true"/>
        </behavior>
        </serviceBehaviors>
        <endpointBehaviors>
            <behavior name="jsonBehavior">
                <crossOriginResourceSharingBehavior />
                <webHttp />          
            </behavior>
        </endpointBehaviors>
    </behaviors>
</system.serviceModel>

2. 新增OPTIONS预检请求处理逻辑

修改CustomHeaderMessageInspector的AfterReceiveRequest方法,直接处理预检请求,终止后续流程直接返回响应:

using System.Net;
using System.ServiceModel.Web;

public class CustomHeaderMessageInspector : IDispatchMessageInspector
{
    Dictionary<string, string> requiredHeaders;
    public CustomHeaderMessageInspector(Dictionary<string, string> headers)
    {
        requiredHeaders = headers ?? new Dictionary<string, string>();
    }
    public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
    {
        // 处理OPTIONS预检请求
        if (WebOperationContext.Current.IncomingRequest.Method == "OPTIONS")
        {
            var response = WebOperationContext.Current.OutgoingResponse;
            response.StatusCode = HttpStatusCode.OK;
            foreach (var item in requiredHeaders)
            {
                response.Headers.Add(item.Key, item.Value);
            }
            // 构造空响应,终止后续流程
            var reply = Message.CreateMessage(MessageVersion.None, "");
            var httpResponse = new HttpResponseMessageProperty
            {
                StatusCode = HttpStatusCode.OK
            };
            reply.Properties[HttpResponseMessageProperty.Name] = httpResponse;
            reply.Properties.Add(WebBodyFormatMessageProperty.Name, new WebBodyFormatMessageProperty(WebContentFormat.Raw));
            throw new FaultException("Preflight handled");
        }
        string displayText = $"Server has received the following message:{Environment.NewLine}{request}{Environment.NewLine}";
        Console.WriteLine(displayText);
        return null;
    }

    public void BeforeSendReply(ref Message reply, object correlationState)
    {
        if (reply.Properties.TryGetValue(HttpResponseMessageProperty.Name, out var httpResponseObj) 
            && httpResponseObj is HttpResponseMessageProperty httpHeader)
        {
            foreach (var item in requiredHeaders)
            {
                // 避免重复添加头
                if (!httpHeader.Headers.AllKeys.Contains(item.Key))
                {
                    httpHeader.Headers.Add(item.Key, item.Value);
                }
            }
        }
    }
}

3. 修正响应头字段名

修改BehaviorAttribute中的错误字段名,补充可选配置:

public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
{
    var requiredHeaders = new Dictionary<string, string>
    {
        { "Access-Control-Allow-Origin", "*" },
        // 修正字段名,将Access-Control-Request-Method改为Access-Control-Allow-Methods
        { "Access-Control-Allow-Methods", "POST,GET,PUT,DELETE,OPTIONS" },
        { "Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With" },
        // 可选:缓存预检请求结果24小时,减少重复请求
        { "Access-Control-Max-Age", "86400" }
    };
    endpointDispatcher.DispatchRuntime.MessageInspectors.Add(new CustomHeaderMessageInspector(requiredHeaders));
}

4. 可选客户端适配

如果POST请求携带自定义头,需要在Access-Control-Allow-Headers中补充对应的头字段名,确保预检请求校验通过。

内容的提问来源于stack exchange,提问作者gmd0123

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.16 23:45:04