ceth
ceth

Reputation: 45285

Response for preflight has invalid HTTP status code 405

I have read many similar problems in StackOverflow, but the solutions doesn't work for me.

I have WCF REST service:

[<OperationContract>]    
    [<WebInvoke(UriTemplate = "PostItem", 
            RequestFormat= WebMessageFormat.Json,   
            ResponseFormat = WebMessageFormat.Json, Method = "POST")>]         

I can use it using Postman (Chrome extension). I am passing data as 'raw', not 'urlencoded'. And I get 200 return code.

enter image description here

I need to call this method using angularjs:

    $http.post('http://192.168.1.65/Service1.svc/restapi/PostItem',                   
                {
    "Address": "г. Москва, ул. Соколово-Мещерская, д.25",
     ...
    "User": ""
      })  

I have just copied URL and JSON from Postman. But I get the error:

angular.js:10722 OPTIONS http://192.168.1.65/Service1.svc/restapi/PostItem http://192.168.1.65/Service1.svc/restapi/PostItem. Response for preflight has invalid HTTP status code 405

I have searched similar problems and have found two solutions:

  1. Use jQuery to set header Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', but it doesn't work with my WCF service
  2. Set custom headers in my Web.Config:

    <httpProtocol>
       <customHeaders>
          <add name="Access-Control-Allow-Origin" value="*" />
          <add name="Access-Control-Allow-Headers" value="Content-Type" />
          <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
       </customHeaders>
    </httpProtocol>
    

It doesn't help me. And I am not sure that the reason of the error on the server side. The Postman extension can call this method succesfully.

How can I make the same POST call using AngularJS ?

Update:

Here is OPTIONS request:

enter image description here

Review and Response tabs are empty

Update 2:

All works fine in IE, but doesn't work in Chrome.

Upvotes: 11

Views: 69309

Answers (6)

Tiago Gouv&#234;a
Tiago Gouv&#234;a

Reputation: 16740

I want to show what work for me.

First you must enable CORS on web.config (like Mihai sad):

<httpProtocol>
  <customHeaders>
    <add name="Access-Control-Allow-Origin" value="*" />
    <add name="Access-Control-Allow-Headers" value="Content-Type" />
    <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE,     OPTIONS" />
  </customHeaders>
</httpProtocol>

If you have some extra HEADER parameter, you must add it to Access-Control-Allow-Headers, like:

<add name="Access-Control-Allow-Headers" value="Content-Type, X-Your-Extra-Header-Key" />

And finally, to handle OPTIONS requests you must reply with empty response, adding in your application class:

protected void Application_BeginRequest()
{
    if (Request.Headers.AllKeys.Contains("Origin") && Request.HttpMethod == "OPTIONS")
    {
        Response.Flush();
    }
}

Upvotes: 25

Tech Enthusiast
Tech Enthusiast

Reputation: 11

Solution that worked for me:

  1. Add this to web.config (server-side):

     <httpProtocol>
      <customHeaders>
        <add name="Access-Control-Allow-Origin" value="*" />
        <add name="Access-Control-Allow-Headers" value="Content-Type" />
        <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE,  OPTIONS" />
      </customHeaders>
    </httpProtocol>
    
  2. Create a Global.asax file (Global application class) and add the following code:

        protected void Application_BeginRequest(object sender, EventArgs e){
            if (Request.Headers.AllKeys.Contains("Origin") && Request.HttpMethod == "OPTIONS")
                {
                    Response.Flush();
                }
        }
    

Upvotes: 0

muinh
muinh

Reputation: 605

I have just solved the same problem with deleting xhr.setRequestHeader() in my AJAX request. If someone has one in code, try to remove it.

Upvotes: 0

Jes&#250;s L&#243;pez
Jes&#250;s L&#243;pez

Reputation: 9221

Since IIS Team published IIS CORS module hacks like empty methods are not needed anymore. It deals with CORS including preflight requests properly. You can configure it in the web config for example:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <cors enabled="true" failUnlistedOrigins="true">
            <add origin="*" />
            <add origin="https://*.microsoft.com"
                 allowCredentials="true"
                 maxAge="120"> 
                <allowHeaders allowAllRequestedHeaders="true">
                    <add header="header1" />
                    <add header="header2" />
                </allowHeaders>
                <allowMethods>
                     <add method="DELETE" />
                </allowMethods>
                <exposeHeaders>
                    <add header="header1" />
                    <add header="header2" />
                </exposeHeaders>
            </add>
            <add origin="http://*" allowed="false" />
        </cors>
    </system.webServer>
</configuration>

Upvotes: 0

Morvael
Morvael

Reputation: 3567

Although this already has an answer, but heres my solution. In the web config you have to remove the instruction to <remove name="OPTIONSVerbHandler" />

First add in the customHeaders

<httpProtocol>
  <!-- THESE HEADERS ARE IMPORTANT TO WORK WITH CORS -->
  <customHeaders>
    <add name="Access-Control-Allow-Origin" value="*" />
    <add name="Access-Control-Allow-Methods" value="POST, PUT, DELETE, GET, OPTIONS" />
    <add name="Access-Control-Allow-Headers" value="content-Type, accept, origin, X-Requested-With, X-Authentication, name" />
  </customHeaders>
</httpProtocol>

Then either comment out or delete the instruction to remove the OPTIONSverbHandler

<handlers>
  <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
  <!-- <remove name="OPTIONSVerbHandler" /> -->
  <remove name="TRACEVerbHandler" />
  <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>

Upvotes: 2

ceth
ceth

Reputation: 45285

Looks like I have found solution. I just added second method:

[<OperationContract>]    
[<WebInvoke(UriTemplate = "PostTest", 
        RequestFormat= WebMessageFormat.Json,   
        ResponseFormat = WebMessageFormat.Json, Method = "POST")>]         
abstract PostTest: obj: Test -> unit

[<OperationContract>]    
[<WebInvoke(UriTemplate = "PostTest", 
        RequestFormat= WebMessageFormat.Json,   
        ResponseFormat = WebMessageFormat.Json, Method = "OPTIONS")>]         
abstract PostTestOptions: unit -> unit

It is just empty methods that do nothing. I don't know the reason, but all is working.

Upvotes: 7

Related Questions