November Happy Hour will be moved to Thursday December 5th.

Headless API - 404 Not Found

Vote:
 

We've got an issue with the headless content api, in some cases.

Everything works fine while we're running local dev on IIS Express, both firendly-url (which our Angular app relies on) as well as /api/episerver/v2.0/content/XXXX requests works. However, after deploying to Azure, we get a 404 Not Found from the content api-request. Though making the same CURL request to https://AZURE/api/episerver/v2.0/content/XXXX does work. So it seems like the content-api works, but there's some configuration differences web server-wise. 

We've managed to reproduce the error locally by setting up a stand alone IIS server for the site, but it's a bit hard to debug this issue. Does anyone have any suggestions what could be causing this?

We've followed setup and configuration:

https://world.episerver.com/documentation/developer-guides/content-delivery-api/configuration/

https://world.episerver.com/documentation/developer-guides/content-delivery-api/using-friendly-urls/

  • Latest version (ContentApi 2.4.0, no search, no OAuth)
  • Utilizing Friendly urls (Accept headers, content-type 'application/json' and language are set) 
#203723
Edited, May 03, 2019 16:50
Vote:
 

Yes, without success.

#203743
May 06, 2019 8:33
Vote:
 

I've turned on some logging for two requests, one straight to the content API which is successful. And one that fails, utilizing friendlyUrls.

Successful content API request:

INFO EPiServer.ContentApi.Core.InitializationService: Start initializing virtual role for Headless APi
DEBUG EPiServer.Shell.Web.Routing.ModuleRouteCollection: Not routing '~/api/episerver/v2.0/content/18949' since it doesn't start with '~/EPiServer/EPiServer.Labs.LanguageManager/3.2.0'
...
DEBUG EPiServer.Shell.Web.Routing.ModuleRouteCollection: Not routing '~/api/episerver/v2.0/content/18949' since it doesn't start with '~/modules'
DEBUG EPiServer.Web.TemplateResolver: CustomerServiceStartPage: Selected CustWeb.UI.Controllers.Pages.CustomerServiceStartPageController. (tag='', channel='web', category='Request')
DEBUG EPiServer.Web.TemplateResolver: StartPage: Selected CustWeb.UI.Controllers.Pages.StartPageController. (tag='', channel='web', category='Request')
DEBUG EPiServer.Web.TemplateResolver: CustomerServiceStartPage: Selected CustWeb.UI.Controllers.Pages.CustomerServiceStartPageController. (tag='', channel='web', category='Request')
DEBUG EPiServer.Web.TemplateResolver: ImageFile: Selected EPiServer.CdnSupport.CdnMediaHandler. (tag='', channel='web', category='Request')
DEBUG BVNetwork.NotFound.Core.CustomRedirects.CustomRedirectHandler: Begin: Get Current CustomRedirectHandler
DEBUG BVNetwork.NotFound.Core.CustomRedirects.CustomRedirectHandler: Returning cached handler.
DEBUG BVNetwork.NotFound.Core.CustomRedirects.CustomRedirectHandler: End: Get Current CustomRedirectHandler
DEBUG BVNetwork.NotFound.Core.RequestHandler: Not a 404 response.
Request URL: http://ENVIRONMENT/api/episerver/v2.0/content/18949
Response status code: 200

Erroneous friendlyUrl request (Accept header 'application/json'):

INFO EPiServer.ContentApi.Core.InitializationService: Start initializing virtual role for Headless APi
DEBUG EPiServer.Shell.Web.Routing.ModuleRouteCollection: Not routing '~/nks' since it doesn't start with '~/EPiServer/EPiServer.Labs.LanguageManager/3.2.0'
...
DEBUG EPiServer.Shell.Web.Routing.ModuleRouteCollection: Not routing '~/nks' since it doesn't start with '~/modules'
DEBUG EPiServer.Web.Routing.Segments.Internal.NodeSegment: Url 'http://ENVIRONMENT/nks' was routed to content with id '18949' and language was set to 'sv'
DEBUG EPiServer.Web.TemplateResolver: CustomerServiceStartPage: Selected CustWeb.UI.Controllers.Pages.CustomerServiceStartPageController. (tag='', channel='web', category='MvcController')
DEBUG EPiServer.Web.Routing.Segments.Internal.NodeSegment: Url 'http://ENVIRONMENT/api/episerver/v2.0/content/18949' was routed to content with id '1' and language was set to ''
DEBUG BVNetwork.NotFound.Core.CustomRedirects.CustomRedirectHandler: Begin: Get Current CustomRedirectHandler
DEBUG BVNetwork.NotFound.Core.CustomRedirects.CustomRedirectHandler: Returning cached handler.
DEBUG BVNetwork.NotFound.Core.CustomRedirects.CustomRedirectHandler: End: Get Current CustomRedirectHandler
DEBUG BVNetwork.NotFound.Core.RequestHandler: Handling 404 request.
Request URL: http://ENVIRONMENT/api/episerver/v2.0/content/18949
Response status code: 404

The line: DEBUG EPiServer.Web.Routing.Segments.Internal.NodeSegment: Url 'http://ENVIRONMENT/api/episerver/v2.0/content/18949' was routed to content with id '1' and language was set to ' ' seems really strange to me here. 

#203791
May 07, 2019 12:44
Vote:
 

Hi Michael,

 1. Does your site have any custom routing ? ContentDeliveryAPi's custom routing and yours (or routing in other products e.g Commerce) may step on each other so causing conflict. This is just my guess.

 2. ContentDeliveryAPi's friendly url feature may not work with SimpleAddress.

 3. So, till now you're able to reproduce the error on your local machine with stand alone IIS Server ? We'd like to know the steps to reproduce the error so we can dig deeper. 

#203822
May 08, 2019 5:55
Vote:
 

Hello Michael and Quan

I would be really interested in a solution a well :). We have the same problem.

The Content API url works (direct postman call to: http://xxxx.localhost/api/episerver/v2.0/content/3683/children works).

The Search Content url works (direct postmand call to http://xxxx.localhost/api/episerver/v2.0/search/content/?filter=tolower(name) eq 'vuetest' works)

But the friendly url routing does seem to not work.

It does find the correct url redirect if you look at the log: http://xxxx.localhost/en/vuetest/children => http://xxxx.localhost/api/episerver/v2.0/content/3683/children

But it seems the accept-language header value is lost somehow or the ID gets lost because it ends up with 1?

Quan: What do you mean with 'SimpleAddress'?

Kind regards

Remco

Error:

2019-05-08 08:37:36,005 [29] DEBUG EPiServer.Shell.Web.Routing.ModuleRouteCollection: Not routing '~/en/vuetest/children' since it doesn't start with '~/modules'
2019-05-08 08:37:36,006 [29] DEBUG EPiServer.Web.Routing.Segments.Internal.NodeSegment: Url 'http://xxxx.localhost/en/vuetest/children' was routed to content with id '3683' and language was set to 'en'
2019-05-08 08:37:36,008 [29] DEBUG EPiServer.Web.TemplateResolver: FrontEndPage: Selected SpecialtyChemicals.Site.Controllers.Pages.FrontEndPageController. (tag='', channel='web', category='MvcController')
2019-05-08 08:37:36,009 [29] DEBUG EPiServer.Web.Routing.Segments.Internal.NodeSegment: Url 'http://xxxx.localhost/api/episerver/v2.0/content/3683/children' was routed to content with id '1' and language was set to 'en'
2019-05-08 08:37:36,010 [29] DEBUG BVNetwork.NotFound.Core.CustomRedirects.CustomRedirectHandler: Begin: Get Current CustomRedirectHandler
2019-05-08 08:37:36,011 [29] DEBUG BVNetwork.NotFound.Core.CustomRedirects.CustomRedirectHandler: Returning cached handler.
2019-05-08 08:37:36,012 [29] DEBUG BVNetwork.NotFound.Core.CustomRedirects.CustomRedirectHandler: End: Get Current CustomRedirectHandler
2019-05-08 08:37:36,012 [29] DEBUG BVNetwork.NotFound.Core.RequestHandler: Handling 404 request.
Request URL: http://xxxx.localhost/api/episerver/v2.0/content/3683/children
Response status code: 404

#203829
May 08, 2019 8:50
Vote:
 

Hi Quan!

  1. Yes we have some custom routing (but no extra products like Commerce), during the day I'll try to rule that out. Bit strange that we get it fully working with IIS Express though, routing behaviour should be the same (?) 
  2. Not sure what you mean here?
  3. Yes we get the same 404 while running stand alone IIS locally. But if it's the exact same reason behind it I couldn't tell (but for now let's assume it is). After 1) We'll set up a new Alloy site with ContentDelivery API on our stand alone IIS and IIS Express to see if it differs.  

Just for brevity, I'll include the succsessful request log for IIS Express:

INFO EPiServer.ContentApi.Core.InitializationService: Start initializing virtual role for Headless APi
DEBUG EPiServer.Shell.Web.Routing.ModuleRouteCollection: Not routing '~/nks' since it doesn't start with '~/EPiServer/EPiServer.Labs.LanguageManager/3.2.0'
DEBUG EPiServer.Shell.Web.Routing.ModuleRouteCollection: Not routing '~/nks' since it doesn't start with '~/modules'
DEBUG EPiServer.Web.Routing.Segments.Internal.NodeSegment: Url 'https://ENVIRONMENT:44302/nks' was routed to content with id '18949' and language was set to 'sv'
DEBUG EPiServer.Web.TemplateResolver: CustomerServiceStartPage: Selected CustWeb.UI.Controllers.Pages.CustomerServiceStartPageController. (tag='', channel='web', category='MvcController')
DEBUG EPiServer.Web.Routing.Segments.Internal.NodeSegment: Url 'https://ENVIRONMENT:44302/api/episerver/v2.0/content/18949' was routed to content with id '1' and language was set to ''
INFO EPiServer.ContentApi.Core.InitializationService: Start initializing virtual role for Headless APi
DEBUG EPiServer.Shell.Web.Routing.ModuleRouteCollection: Not routing '~/api/episerver/v2.0/content/18949' since it doesn't start with '~/EPiServer/EPiServer.Labs.LanguageManager/3.2.0'
DEBUG EPiServer.Shell.Web.Routing.ModuleRouteCollection: Not routing '~/api/episerver/v2.0/content/18949' since it doesn't start with '~/modules'
DEBUG EPiServer.Web.TemplateResolver: CustomerServiceStartPage: Selected CustWeb.UI.Controllers.Pages.CustomerServiceStartPageController. (tag='', channel='web', category='Request')
DEBUG EPiServer.Web.TemplateResolver: StartPage: Selected CustWeb.UI.Controllers.Pages.StartPageController. (tag='', channel='web', category='Request')
DEBUG EPiServer.Web.TemplateResolver: CustomerServiceStartPage: Selected CustWeb.UI.Controllers.Pages.CustomerServiceStartPageController. (tag='', channel='web', category='Request')
DEBUG EPiServer.Web.TemplateResolver: ImageFile: Selected EPiServer.Web.Internal.ContentMediaHttpHandler. (tag='', channel='web', category='Request')
DEBUG BVNetwork.NotFound.Core.CustomRedirects.CustomRedirectHandler: Begin: Get Current CustomRedirectHandler
DEBUG BVNetwork.NotFound.Core.CustomRedirects.CustomRedirectHandler: Returning cached handler.
DEBUG BVNetwork.NotFound.Core.CustomRedirects.CustomRedirectHandler: End: Get Current CustomRedirectHandler
DEBUG BVNetwork.NotFound.Core.RequestHandler: Not a 404 response.
Request URL: https://ENVIRONMENT:44302/api/episerver/v2.0/content/18949
Response status code: 200
#203830
Edited, May 08, 2019 9:05
Vote:
 

Hi Remco and Michael,

Thanks a lot for your information

1. I mean SimpleAress in EditMode. If we use SimpleAdress to get content's ancestors or children it may not work (this is the limitation of ContentDeliveryApi)

2. ContentApi's partial router may disrupt other routers in the site (or vice-versa).

This can disrupt other partial routers in the site because the request URL is rewritten. To solve this problem, follow these steps:

  • Create a new class (for example, CustomContentApiRouteService) that inherits ContentApiRouteService  and then, register a transient lifecycled implementation for a ContentApiRouteService in the initialization service.
  • Override the function ShouldRouteRequest to prevent the URL from being re-written in unexpected cases. For example, requests whose accept types contain application/json are currently handled by our partial router (accept type application/json is a common header). So, you can add one more header (for example, Routed-By-ContentApi) for CD-related requests and then, use this header in the function to decide whether our partial router should handle the request and rewrite URL later on. 

For example

using EPiServer.ContentApi.Routing;
using System.Web;

public class CustomContentApiRouteService : ContentApiRouteService
{
    public override bool ShouldRouteRequest(HttpRequestBase request)
    {
        // By default, Requests which have accept headers 'application/json' will be routed.
        //if (request != null && request.AcceptTypes?.Contains(RouteConstants.JsonContentType) == true)
        //{
        //    return true;
        //}

        bool isRoutedByContentApi = false;
        if (bool.TryParse(request.Headers["Route-By-ContentApi"], out isRoutedByContentApi))
        {
            return isRoutedByContentApi;
        }

        return false;
    }
}

3. If you have configuration handlers in web.config like below, ContentApi friendly url will throw 404. The order of handlers should be reversed (or you can try removing StaticFileHandler)

We're sill trying to figure out the root cause.

If one of these approaches works for you, please let us know.

Thanks again!

#203834
Edited, May 08, 2019 11:12
Vote:
 

Hi Quan

Thanks for the fast response.

  1. we dont use SimpleAddress
  2. You are refering to this page: https://world.episerver.com/documentation/developer-guides/content-delivery-api/using-friendly-urls/
    I thought I tried this already but I will try again, maybe I missed something.
  3. This does not make any difference in our solution

#203835
May 08, 2019 11:36
Vote:
 

Hi Quan,

  1. We don't use "simple adress"
  2. We've done this and it wasn't the solution unfortunately. 
  3. We tried to temporary remove some of the handlers we had without success, however we found some differences in our web.config and the working Alloy web.config. Namely:
    under <system.WebServer><handlers>

Not working:

    <handlers>
      <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="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" 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="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
      <add name="UrlRoutingHandler" preCondition="integratedMode" verb="*" path="UrlRouting.axd" type="System.Web.HttpForbiddenHandler, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
    </handlers>

Working:

    <handlers>
      <remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" />
      <remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
      <add name="UrlRoutingHandler" preCondition="integratedMode" verb="*" path="UrlRouting.axd" type="System.Web.HttpForbiddenHandler, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
    </handlers>

I don't have an explanation to why, but maby you have? At least it's working now :) 

#203836
Edited, May 08, 2019 14:11
Vote:
 

Yes this works on our system as well.

Thank you Michael!

#203837
May 08, 2019 14:18
Vote:
 

Nice Remco!

I don't know to why this is, but it feels strange that we had the preCondition classicMode since the site runs in integrated-mode. I'm fairly new in this project so don't know the history but maybe it's just legacy stuff in our web.config. 

#203838
Edited, May 08, 2019 14:30
Vote:
 

excellent !

It's good to hear that, Michael.

#203871
May 09, 2019 8:19
This topic was created over six months ago and has been resolved. If you have a similar question, please create a new topic and refer to this one.
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.