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

8
我有一个使用aspnetcorereactjs生成的股票应用程序,该应用程序从起始模板(dotnet new react)生成。我想要将这个SPA应用程序从根url的子路径中提供服务,例如,不是样例应用程序的url是https://localhost:5001/counter,我希望它的url改为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 谢谢!

你有没有偶然解决这个问题? - Shoe
我刚在Azure上完成了测试。请查看我的回答,敬礼。 - Roar S.
3个回答

4

你可以通过以下方式来实现:

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]


React开发服务器代理如何与.Net Framework 4.6设置?使用.Net Core很容易使用UseReactDevelopmentServer,但在.Net Framework中不可用。 - user2966445

4

首先,将应用程序移动到子路径中,通过在package.json的顶部添加以下内容:

"homepage": "/myapp/", 

在ClientApp文件夹中运行npm start时,应用程序现在正在服务于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等平台的更改之前,不要忘记清除浏览器历史记录。


0
我将每个答案的部分组合起来使其工作。 你需要在 package.json 中添加 "homepage": "/myapp",以及对 Startup.cs 进行配置更改。我使用了Shoe's answer中提供的更简单的配置,没有所有额外的缓存和套接字指令,因为我不需要那些。
因为我的应用程序还在/myapp下使用React Router进行SPA路由,所以我还需要将basename添加到根BrowserRouter<BrowserRouter basename="/myapp" >...</BrowserRouter>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接