ngDeveloper
ngDeveloper

Reputation: 1304

Request returns 404 Not Found for OPTIONS, but works fine when using Postman (ASP.NET)?

Browser console output:

XMLHttpRequest cannot load https://api.[...].com/[...]. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access. The response had HTTP status code 404.

I have an AngularJS application that is making calls to an API built in ASP.NET. Recently the backend team added versioning to the application, and for some reason, one of the API endpoints will no longer return 200 OK for the OPTIONS request (even though all the other API endpoints on that same server still return 200 OK). Always return 404 Not Found.

ASP.NET server seems to be using a WebApi.Cors package; no specific [HttpOptions] methods are being declared (all OPTIONS request are handled through the package); and the web.config feeds the CorsConfig with * for all of origin, headers, methods.

I've tried many of the solutions from Google results but nothing has worked.

Anyone face a similar issue and can give general guidance on what could be causing the issue, or how to potentially test for the problem, or attempt a solution?

[Edit:] Found solution.

Issue caused because "Version 1" of the API endpoint was dropped on that specific route. The first valid version on that endpoint was now "Version 2". So I added a blank Controller method to catch requests for "Version 1" (which only returns a blank string, nothing more), and this was sufficient to allow the OPTION request to resolve.

Upvotes: 1

Views: 9029

Answers (2)

ngDeveloper
ngDeveloper

Reputation: 1304

Found the solution. Posting it here for anyone else that has the problem in the future.

The API endpoint started with "version 2". There had been an earlier "version 1" that never made it to production, but it was dropped/discontinued because the signature would be completely changing. This was done because development teams had been using "version 1" up to that point, but since it wasn't going into production, logic dictated no longer having that version/endpoint.

For some reason, not having a "version 1" caused the OPTIONS to fail and return a 404 Not Found. My guess is because the required version header was not actually included with the OPTIONS pre-flight request, so it never resolved to a GET destination in the Controller.

Thus, you must have a version 1 reference, even if it's a placeholder that just returns a blank string.

Before:

[VersionedRoute("products", 2, Name = "GetProducts")]
[HttpGet]
public IHttpActionResult GetProducts([FromUri] GetProductsRequest request)
{

After:

[VersionedRoute("products", 1, Name = "GetProducts")]
[HttpGet]
public IHttpActionResult GetProducts()
{
    return NotFound();
}

[VersionedRoute("products", 2, Name = "GetProducts_V2")]
[HttpGet]
public IHttpActionResult GetProducts_V2([FromUri] GetProductsRequest request)
{

Upvotes: -1

Seany84
Seany84

Reputation: 5596

I think part of the issue here is the routing has changed:

Recently the backend team added versioning to the application

Things to check:

  1. WebApi Configuration

Can you make sure that your configuration takes place as the first item in your Global.asax file:

void Application_Start(object sender, EventArgs e)
{
     GlobalConfiguration.Configure(WebApiConfig.Register);
     //...
}
  1. Web API Routing

Has the versioniong been correctly configured inside the WebApiConfig?

public static void Register(HttpConfiguration config)
{
     config.EnableCors(new EnableCorsAttribute("*", "*", "*");

     config.Routes.MapHttpRoute(
         name: "DefaultApi",
         routeTemplate: "api/v2/{controller}/{id}",
         defaults: new { id = RouteParameter.Optional }
}

In IIS 7.5 the only way I got CORS working was via the web.config and not through the Nuget package:

My web.config was as follows:

      <remove name="OPTIONSVerbHandler" />
      <remove name="TRACEVerbHandler" />

      <remove name="ExtensionLessUrlHandler-ISAPI-4.0_32bit" />
      <remove name="ExtensionLessUrlHandler-ISAPI-4.0_64bit" />
      <remove name="ExtensionLessUrlHandler-Integrated-4.0" />

      <add name="ExtensionLessUrlHandler-ISAPI-4.0_32bit" path="*." verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
     <add name="ExtensionLessUrlHandler-ISAPI-4.0_64bit" path="*." verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    </handlers>
</system.webServer>

Upvotes: 2

Related Questions