aspnetcore icon indicating copy to clipboard operation
aspnetcore copied to clipboard

The SPA default page middleware could not return the default page '/index.html' in production application

Open danobri opened this issue 6 years ago • 103 comments

I have an ASP.Net Core / Angular 5 application that is logging errors to the Windows Event Log in our production environment. The following error is getting logged frequently but intermittently in production, and I have no idea why. The application is definitely in production mode, has been published, and is functioning.

System.InvalidOperationException: The SPA default page middleware could not return the default page '/index.html' because it was not found, and no other middleware handled the request. Your application is running in Production mode, so make sure it has been published, or that you have built your SPA manually. Alternatively you may wish to switch to the Development environment.

AFAIK no users are experiencing a problem with the site when these errors occur. Any idea why these errors are being thrown, and whether there is in fact a problem that needs to be addressed?

danobri avatar Jul 25 '18 02:07 danobri

Do angular output directory and specified path in services.AddSpaStaticFiles(configuration => configuration.RootPath = $"your/output/path"); match? Files in the specified folder must be computed to publish in your .csproj file like this:

  <Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish">
    <!-- Include the newly-built files in the publish output -->
    <ItemGroup>
      <DistFiles Include="your\output\path\**" />
      <ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">
        <RelativePath>%(DistFiles.Identity)</RelativePath>
        <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
      </ResolvedFileToPublish>
    </ItemGroup>
  </Target>

Spaier avatar Jul 25 '18 14:07 Spaier

I am setting the RootPath to the Angular dist folder:

services.AddSpaStaticFiles(configuration =>
{
  configuration.RootPath = "ClientApp/dist";
});

And here is what's in my .csproj file:

<PropertyGroup>
    <TargetFramework>netcoreapp2.0</TargetFramework>
    <TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
    <IsPackable>false</IsPackable>
    <SpaRoot>ClientApp\</SpaRoot>
    <DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
    <!-- Set this to true if you enable server-side prerendering -->
    <BuildServerSideRenderer>false</BuildServerSideRenderer>
</PropertyGroup>

<Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish">
    <!-- As part of publishing, ensure the JS resources are freshly built in production mode -->
    <Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
    <Exec WorkingDirectory="$(SpaRoot)" Command="npm run build -- --prod" />
    <Exec WorkingDirectory="$(SpaRoot)" Command="npm run build:ssr -- --prod" Condition=" '$(BuildServerSideRenderer)' == 'true' " />

    <!-- Include the newly-built files in the publish output -->
    <ItemGroup>
      <DistFiles Include="$(SpaRoot)dist\**; $(SpaRoot)dist-server\**" />
      <DistFiles Include="$(SpaRoot)node_modules\**" Condition="'$(BuildServerSideRenderer)' == 'true'" />
      <ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">
        <RelativePath>%(DistFiles.Identity)</RelativePath>
        <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
      </ResolvedFileToPublish>
    </ItemGroup>
  </Target>

I'm wondering if my problem is that I still have the SSR build instructions in the csproj even though SSR is not enabled, and dist-server does not exist..?

danobri avatar Jul 25 '18 15:07 danobri

SSR isn't the problem. You should set path in ConfigureServices() method via services.AddSpaStaticFiles(configuration => configuration.RootPath = $"ClientApp/dist");. Then in Configure you shouldn't specify source path:

app.UseSpaStaticFiles();
app.UseSpa(configuration => { /*spa.Options.SourcePath = "ClientApp";*/ });

spa.Options.SourcePath is only used in development build judging from its' description.

Spaier avatar Jul 25 '18 15:07 Spaier

Sorry - not sure if you saw my edit, but I was in fact setting the RootPath correctly, I was just looking in the wrong place. :) I will try removing the SourcePath setting, however, I'm fairly certain this configuration came with the dotnet new angular template. What is the SourcePath setting used for and why shouldn't it be set?

danobri avatar Jul 25 '18 15:07 danobri

This is used to determine the folder where package.json scripts should be executed. Like new AngularCliBuilder(npmScript: "build:ssr") or spa.UseAngularCliServer(npmScript: "start");.

app.UseSpa(spa =>
{
    spa.Options.SourcePath = "ClientApp";

    spa.UseSpaPrerendering(options =>
    {
        options.BootModulePath = $"{spa.Options.SourcePath}/dist-server/main.bundle.js";
        options.BootModuleBuilder = env.IsDevelopment()
            ? new AngularCliBuilder(npmScript: "build:ssr")
            : null;
        options.ExcludeUrls = new[] { "/sockjs-node" };
    });

    if (env.IsDevelopment())
    {
        spa.UseAngularCliServer(npmScript: "start");
    }
});

Spaier avatar Jul 25 '18 15:07 Spaier

Thanks - I am using a proxy:

spa.UseProxyToSpaDevelopmentServer("https://localhost:4200");

So sounds like I probably don't need the SourcePath setting. That said - are you saying the SourcePath setting is the cause of the errors in my production environment?

danobri avatar Jul 25 '18 15:07 danobri

No, SourcePath does nothing if you use proxy during development. Application probably can't find index.html because it wasn't specified like this: services.AddSpaStaticFiles(configuration => configuration.RootPath = $"ClientApp/dist");

Spaier avatar Jul 25 '18 16:07 Spaier

I think maybe you aren't seeing the edits I made to my original response. I am setting the RootPath as suggested. (Maybe try refreshing the this Github page to ensure you are seeing the latest content).

danobri avatar Jul 25 '18 16:07 danobri

Now I see it. Can you show what's inside of UseSpa()?

Spaier avatar Jul 25 '18 16:07 Spaier

Not much... Will of course remove the SourcePath setting since it's not needed, but this is what is currently in production:

app.UseSpa(spa =>
{
  spa.Options.SourcePath = "ClientApp";
  
  if (env.IsDevelopment())
  {
    spa.UseProxyToSpaDevelopmentServer("https://localhost:4200");
  }
});

danobri avatar Jul 25 '18 16:07 danobri

Is index.html present after build in ClientApp/dist? I'd try to remove node_modules and install again, remove SourcePath and redeploy.

Spaier avatar Jul 25 '18 16:07 Spaier

Index.html is present in clientapp/dist, otherwise the application wouldn't function at all - that is what is confusing about the error message. The error is being logged in a production application that seems to working fine. I will try removing the node_modules folder locally, and then rebuild and republish and see if that makes a difference. What makes you think that will resolve the error?

danobri avatar Jul 25 '18 17:07 danobri

Removing the node_modules folder and republishing did not solve the issue - still seeing quite a few of these errors logged on the production server. Any idea why that would be?

danobri avatar Aug 10 '18 00:08 danobri

I'm seeing the same issue as @danobri on a production site that appears to be working fine otherwise. The exceptions are intermittent, but persistent. I'm using the Angular spa template pretty much straight away with SSR enabled.

joshberry avatar Aug 27 '18 12:08 joshberry

It's an IIS Default Document issue. Just add the following to your web.config:

<system.webServer>
   ...
      <defaultDocument enabled="false" />
</system.webServer>

joshpearce avatar Aug 31 '18 20:08 joshpearce

I have this same issue in production - using SPA for react. Everything about the site works fine - except for getting this exception.
Got the exception near initial deployment....then received about 100 of the exceptions within a couple of minutes around 8 hour later (was it an app pool reset?). I cannot make it happen by resetting the pool, etc. I did not experience the error on 2.1.2, but started getting it with 2.1.3 (however it is intermittent - so may not be determining factor)

waynebrantley avatar Sep 11 '18 13:09 waynebrantley

So, it was our vulnerability scanner that caused the exceptions to be generated. This means I can now reproduce it by scanning the IP this core app is installed on. I tried the defaultDocument enabled=false in web.config, with no success. (running scanner gave errors again)

Any ideas @SteveSandersonMS ?

waynebrantley avatar Sep 11 '18 20:09 waynebrantley

I'm also getting this error randomly in a couple of production sites that work just fine.

ASP.NET Core 2.1, using React 16 in the front end.

Below are the relevant parts of my Startup class. I get these notifications at off hours so it might be some scanner. Nothing critical but I'd love to solve it. Any help appreciated. Thanks!

        services.AddSpaStaticFiles(configuration =>
        {
            configuration.RootPath = "ClientApp/build";
        });


        app.UseSpa(spa =>
        {
            spa.Options.SourcePath = "ClientApp";

            if (env.IsDevelopment())
            {
                spa.UseReactDevelopmentServer(npmScript: "start");
            }
        });

grascioni avatar Sep 13 '18 14:09 grascioni

Here is our case for past 2 days. It is really random. We have 3 servers and one of them barely has this issue in last 48 hours but it did have a lot before that.

image

maxisam avatar Sep 27 '18 14:09 maxisam

This happened to my Azure App Service. All I had to do was to restart the service. Worked like charm.

mjtpena avatar Oct 12 '18 17:10 mjtpena

check angular.json file use "outputPath": "dist",

And Startup file

services.AddSpaStaticFiles(configuration => { configuration.RootPath = "ClientApp/dist"; });

addikhann avatar Oct 15 '18 13:10 addikhann

My case is a reactjs app. Also, restarting the service does not help. The service is not down. It is a error caused by requests from vulnerability scanners (or from systems trying to exploit the vulnerability)

waynebrantley avatar Oct 15 '18 23:10 waynebrantley

I can't even get a dotnet new react to start in production (building with dotnet publish -c Release) without it throwing this exception: System.InvalidOperationException: The SPA default page middleware could not return the default page '/index.html' because it was not found, and no other middleware handled the request...

Seems like there is definitely a bug in the building process of the spa somewhere?

@SteveSandersonMS @Eilon

CodySchrank avatar Oct 23 '18 18:10 CodySchrank

@ryanbrandenburg / @mkArtakMSFT - any ideas?

Eilon avatar Oct 23 '18 18:10 Eilon

So the reason we're getting this is someone is trying to POST AND OPTIONS to /index.html not GET. Which causes this error message and causes a 500 error.

Of course of Azure/IIS sees too many errors in too short a time it tries and recycles the app. the problem is that it's doing it over and over again which causes everything in that App Service Plan to crash. :<

How do we properly handle this without the site throwing a 500 error?

Note that this only happens in production, not development and as far as I can tell there is no way to handle this error with your own route. This is a major DOS attack vector in spa services that needs to be fixed ASAP.

JohnGalt1717 avatar Oct 26 '18 12:10 JohnGalt1717

Would be nice if an error wasn't the default behavior. I was able to prevent the exceptions using a rewrite rule in my web.config.

<rewrite>
  <rules>
    <rule name="Prevent requests to index">
      <match url="^index\.html$" />
      <action type="Redirect" url="/" redirectType="Permanent" appendQueryString="true" />
    </rule>
  </rules>
</rewrite>

joshberry avatar Oct 30 '18 15:10 joshberry

I also had this issue what I did is use the rewrite middleware by doing the below.

app.UseRewriter(new RewriteOptions()
                .AddRedirect("index.html", "/"));

rpmansion avatar Oct 30 '18 17:10 rpmansion

I would really like to see the root of this problem solved. We have a .net core 2.1 app with the latest React version, no web config since we are using json files for environment variables. We are randomly getting this error several times at once. Most of the time it's fine and then randomly it will happen a dozen times. The redirect seems to just be a work around and not solve the root issue.

rachelfreeman avatar Oct 30 '18 22:10 rachelfreeman

Anyone has got a solution for this? I'm facing the same issue, can't get the app deployed successfully..

yakeer avatar Nov 11 '18 10:11 yakeer

Seems like these javascript services are unsupported? @SteveSandersonMS can you advise what course of action to take?

waynebrantley avatar Nov 11 '18 18:11 waynebrantley