OPTIONS Method not allowed. Get Works but not POST

2019-06-02 06:03发布

I am using angularJS and this is my code in a factory which makes a http POST call

var data = { ticket: JSON.stringify(aticket), "autoAssignDefaultSLA": "true", "autoAssignDefaultPriority": "true" };

            return $http({
                method: 'POST',
                url: requestUrl,
                data: data,
                headers: { 'Content-Type': 'application/json; charset=UTF-8' }
            });

An http GET call works and I get json back with no issues

return $http({
                method: 'GET',
                url: requestUrl,
                params: { userToken: userToken, assignedIds: contactId, companyIds: "" }
            });

By setting the Content-Type to application/json an OPTIONS request is sent out. So far in my tests it appears that setting the content type to "application/x-www-form-urlencoded" is not possible because the web service will only accept json data. I do not have access to modify the web service code. Another team takes care of that.

The request headers that goes with OPTIONS is

Host: staging.url.com
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:48.0) Gecko/20100101 Firefox/48.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
DNT: 1
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type
Origin: https://url.synbeta.com
Connection: keep-alive

The response headers is as follows

Access-Control-Allow-Headers: Authorization, Content-Type, If-None-Match, Cookie, Cookies, x-session-id, x-atg-host
Access-Control-Allow-Methods: GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS
Access-Control-Allow-Origin: *
Allow: POST
Cache-Control: private
Content-Length: 1565
Content-Type: text/html; charset=UTF-8
Date: Thu, 30 Jun 2016 16:39:48 GMT
Server: Microsoft-IIS/7.5
Set-Cookie: ASP.NET_SessionId=p5aolcjpwd0qfhqjdbluha1h; path=/; HttpOnly
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET

The method is still not allowed. I get "405 method not allowed".

I think it is because the "Access-Control-Allow-Headers" is sending me types and the "Content-Type" case is not matched.

The client and the server is running on HTTPS.

Any insights?

angular version: 1.5.7

Update

The web service developer followed this guide to enable CORS on the server and it worked. http://enable-cors.org/server_wcf.html

1条回答
Evening l夕情丶
2楼-- · 2019-06-02 07:06

From the above answer and the URL mentioned http://enable-cors.org/server_wcf.html

Create Message Inspector

public class CustomHeaderMessageInspector : IDispatchMessageInspector
            {
                Dictionary<string, string> requiredHeaders;
                public CustomHeaderMessageInspector (Dictionary<string, string> headers)
                {
                    requiredHeaders = headers ?? new Dictionary<string, string>();
                }

                public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)
                {
                    return null;
                }

                public void BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
                {
                    var httpHeader = reply.Properties["httpResponse"] as HttpResponseMessageProperty;
                    foreach (var item in requiredHeaders)
                    {
                        httpHeader.Headers.Add(item.Key, item.Value);
                    }           
                }
            }

Create Endpoint Behavior and use Message Inspector to add headers

public class EnableCrossOriginResourceSharingBehavior : BehaviorExtensionElement, IEndpointBehavior
            {
                public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
                {

                }

                public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
                {

                }

                public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
                {
                    var requiredHeaders = new Dictionary<string, string>();

                    requiredHeaders.Add("Access-Control-Allow-Origin", "*");
                    requiredHeaders.Add("Access-Control-Request-Method", "POST,GET,PUT,DELETE,OPTIONS");
                    requiredHeaders.Add("Access-Control-Allow-Headers", "X-Requested-With,Content-Type");

                    endpointDispatcher.DispatchRuntime.MessageInspectors.Add(new CustomHeaderMessageInspector(requiredHeaders));
                }

                public void Validate(ServiceEndpoint endpoint)
                {

                }

                public override Type BehaviorType
                {
                    get { return typeof(EnableCrossOriginResourceSharingBehavior); }
                }

                protected override object CreateBehavior()
                {
                    return new EnableCrossOriginResourceSharingBehavior();
                }
            }

Register new behavior in web.config

 <extensions>
              <behaviorExtensions>        
                <add name="crossOriginResourceSharingBehavior" type="Services.Behaviours.EnableCrossOriginResourceSharingBehavior, Services, Version=1.0.0.0, Culture=neutral" />        
              </behaviorExtensions>      
            </extensions>

Add new behavior to endpoint behavior configuration

<endpointBehaviors>      
            <behavior name="jsonBehavior">
                <webHttp />
                <crossOriginResourceSharingBehavior />
            </behavior>
            </endpointBehaviors>

Configure endpoint

<endpoint address="api" binding="webHttpBinding" behaviorConfiguration="jsonBehavior" contract="Service.IServiceContract" />
查看更多
登录 后发表回答