如何使 ASP.NET/React 应用程序从子路径提供 SPA?

IT技术 asp.net reactjs asp.net-core
2021-04-20 21:02:10

我有一个从入门模板 ( )生成的股票aspnetcorereactjs应用程序dotnet new react我希望从根 url 的子路径提供 SPA 应用程序;例如,https://localhost:5001/counter我正在寻找的不是示例应用程序而是从https://localhost:5001/myapp/counter.

我改变了Startup.cs从:

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

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

对此:

app.Map(new Microsoft.AspNetCore.Http.PathString("/myapp"), appMember =>
            {
                appMember.UseSpa(spa =>
                {
                    spa.Options.SourcePath = "ClientApp";

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

这样的作品。如果我浏览https://localhost:5001/myapp/它似乎加载 index.html,但静态文件正试图从根路径而不是子路径加载。

需要更改什么才能使 react 应用程序使用子路径作为根?我希望它在交互式 VS 开发环境和部署时都能工作,可能在 IIS 上。似乎很接近,但我错过了一些东西。

该解决方案的示例演示可在此处获得:https : //github.com/petertirrell/mvc-spa-demo/tree/master/mvc-spa-demo

谢谢!

3个回答

通过将其添加到 package.json 的顶部,开始将应用程序移动到子路径:

"homepage": "/myapp/", 

npm start在 ClientApp 文件夹中运行时,应用程序现在正在提供服务http://localhost:3000/myapp

然后Startup.cs像这样改变

先删除

app.UseSpaStaticFiles()

然后加

        const string spaPath = "/myapp";
        if (env.IsDevelopment())
        {
            app.MapWhen(ctx => ctx.Request.Path.StartsWithSegments(spaPath)
                               || ctx.Request.Path.StartsWithSegments("/sockjs-node"),
                client =>
            {
                client.UseSpa(spa =>
                {
                    spa.Options.SourcePath = "ClientApp";
                    spa.UseReactDevelopmentServer(npmScript: "start");
                });
            });
        }
        else
        {
            app.Map(new PathString(spaPath), client =>
            {
                // `https://github.com/dotnet/aspnetcore/issues/3147`
                client.UseSpaStaticFiles(new StaticFileOptions()
                {
                    OnPrepareResponse = ctx =>
                    {
                        if (ctx.Context.Request.Path.StartsWithSegments($"{spaPath}/static"))
                        {
                            // Cache all static resources for 1 year (versioned file names)
                            var headers = ctx.Context.Response.GetTypedHeaders();
                            headers.CacheControl = new CacheControlHeaderValue
                            {
                                Public = true,
                                MaxAge = TimeSpan.FromDays(365)
                            };
                        }
                        else
                        {
                            // Do not cache explicit `/index.html` or any other files.  See also: `DefaultPageStaticFileOptions` below for implicit "/index.html"
                            var headers = ctx.Context.Response.GetTypedHeaders();
                            headers.CacheControl = new CacheControlHeaderValue
                            {
                                Public = true,
                                MaxAge = TimeSpan.FromDays(0)
                            };
                        }
                    }
                });

                client.UseSpa(spa =>
                {
                    spa.Options.SourcePath = "ClientApp";
                    spa.Options.DefaultPageStaticFileOptions = new StaticFileOptions()
                    {
                        OnPrepareResponse = ctx => {
                            // Do not cache implicit `/index.html`.  See also: `UseSpaStaticFiles` above
                            var headers = ctx.Context.Response.GetTypedHeaders();
                            headers.CacheControl = new CacheControlHeaderValue
                            {
                                Public = true,
                                MaxAge = TimeSpan.FromDays(0)
                            };
                        }
                    };
                });
            });
        }

在第一次在 Azure 上测试更改之前,不要忘记清除浏览器历史记录。

你可以这样做:

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

在您的ConfigureServices和:

string spaPath = "/myapp";
if (env.IsDevelopment())
{
    app.MapWhen(y => y.Request.Path.StartsWithSegments(spaPath), client =>
    {
        client.UseSpa(spa => 
        {
            spa.UseReactDevelopmentServer(npmScript: "start");
        });
    });
}
else
{
    app.Map(new PathString(spaPath), client =>
    {
        client.UseSpaStaticFiles();
        client.UseSpa(spa => {});
    });
}

应当指出的是,在发展我们使用.MapWhen,因为.Map会造成你的静态文件可于/myapp/myapp/[file]而不是/myapp/[file]

如何使用 .Net Framework 4.6 设置 React 开发服务器代理?使用 .Net Core 使用 UseReactDevelopmentServer 很简单,但这在 .Net Framework 中不可用。
2021-05-23 21:02:10

我结合了每个答案中的一些以使其正常工作。您需要添加"homepage": "/myapp"package.json以及配置更改到Startup.cs我使用了Shoe 的答案中提供的更简单的配置,没有所有额外的缓存和套接字指令,因为我不需要这些。

因为我的应用程序还使用了React Router进行 SPA 路由下/myapp我还需要添加basename到根BrowserRouter

<BrowserRouter basename="/myapp" >...</BrowserRouter>