【问题标题】:Index.html of SPA using AngularJs under OWIN results in 404 errors when loading .js and .css resourcesOWIN下使用AngularJs的SPA的Index.html加载.js和.css资源时出现404错误
【发布时间】:2016-06-24 07:00:42
【问题描述】:

我正在构建一个基于 ASP.NET OWIN 的网站(本质上是一个 AngularJs SPA 应用程序)。可以在这里找到解决方案:

https://github.com/dsidirop/PetTrackerOAuth/tree/ffa702c6ffa05fb44b332d1961eb8337da0acdae

该解决方案由两个项目组成:一个项目托管 OWIN/OAuth/WebAPI2,另一个项目托管 SPA(.html、.css、.js 文件)。这两个项目都经过调整,可以在相同的输出目录中输出它们的文件。因此 index.html 和包含 .js/.css 文件的整个文件夹结构最终位于 OWIN 项目的所有 .dll 旁边的 /bin 目录中。我的 Startup.cs 看起来像这样:

public sealed class Startup
{
    public void Configuration(IAppBuilder appBuilder) //0
    {
        var webApiConfiguration = new HttpConfiguration();

        ConfigureOAuth(appBuilder);

        var physicalFileSystem = new PhysicalFileSystem(@".\bin");
        var options = new FileServerOptions { EnableDefaultFiles = true, FileSystem = physicalFileSystem };
        options.StaticFileOptions.FileSystem = physicalFileSystem;
        options.StaticFileOptions.ServeUnknownFileTypes = true;
        options.EnableDirectoryBrowsing = true;
        options.DefaultFilesOptions.DefaultFileNames = new[] { "index.html" };
        appBuilder.UseFileServer(options);

        WebApiConfig.Register(webApiConfiguration);
        appBuilder.UseCors(CorsOptions.AllowAll);
        appBuilder.UseWebApi(webApiConfiguration); //1

        appBuilder.UseNinjectMiddleware(() => NinjectConfig.CreateKernel.Value).UseNinjectWebApi(webApiConfiguration);
    }
    //0 the app parameter is an interface to a builder instance which is be used to compose the application for our owin server
    //1 the userwebapi extension method is responsible for wiring up the aspnet web api to our owin server pipeline

    public void ConfigureOAuth(IAppBuilder app)
    {
        app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions {
            Provider = new SimpleAuthorizationServerProvider(),
            AllowInsecureHttp = true,
            TokenEndpointPath = new PathString("/token"),
            RefreshTokenProvider = new SimpleRefreshTokenProvider(),
            AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30)
        });
        app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
    }
}

我的 web.config 如下所示:

    <?xml version="1.0" encoding="utf-8"?>
    <!--
      For more information on how to configure your ASP.NET application, please visit
      http://go.microsoft.com/fwlink/?LinkId=301879
      -->
    <configuration>
      <configSections>

        <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
      <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 --></configSections>
      <appSettings></appSettings>
      <system.web>
        <compilation debug="true" targetFramework="4.6.1" />
        <httpRuntime targetFramework="4.6.1" />
        <httpModules>
        </httpModules>
      </system.web>
      <system.webServer>
        <handlers>
          <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
          <remove name="OPTIONSVerbHandler" />
          <remove name="TRACEVerbHandler" />
          <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
        </handlers>
        <validation validateIntegratedModeConfiguration="false" />
        <modules>
        </modules>
        <security>
          <requestFiltering>
            <hiddenSegments>
              <remove segment="bin" />
            </hiddenSegments>
          </requestFiltering>
        </security>
      </system.webServer>
      <runtime>
        <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
          <dependentAssembly>
            <assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral" />
            <bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
          </dependentAssembly>
          <dependentAssembly>
            <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
            <bindingRedirect oldVersion="0.0.0.0-8.0.0.0" newVersion="8.0.0.0" />
          </dependentAssembly>
          <dependentAssembly>
            <assemblyIdentity name="Microsoft.Owin.Security.OAuth" publicKeyToken="31bf3856ad364e35" culture="neutral" />
            <bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
          </dependentAssembly>
          <dependentAssembly>
            <assemblyIdentity name="Microsoft.Owin.Security" publicKeyToken="31bf3856ad364e35" culture="neutral" />
            <bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
          </dependentAssembly>
          <dependentAssembly>
            <assemblyIdentity name="System.Web.Http" publicKeyToken="31bf3856ad364e35" culture="neutral" />
            <bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
          </dependentAssembly>
          <dependentAssembly>
            <assemblyIdentity name="Microsoft.Owin.Security.Cookies" publicKeyToken="31bf3856ad364e35" culture="neutral" />
            <bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
          </dependentAssembly>
          <dependentAssembly>
            <assemblyIdentity name="System.Web.Cors" publicKeyToken="31bf3856ad364e35" culture="neutral" />
            <bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
          </dependentAssembly>
          <dependentAssembly>
            <assemblyIdentity name="System.Web.Http.WebHost" publicKeyToken="31bf3856ad364e35" culture="neutral" />
            <bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
          </dependentAssembly>
          <dependentAssembly>
            <assemblyIdentity name="System.Web.Http.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral" />
            <bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
          </dependentAssembly>
          <dependentAssembly>
            <assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
            <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
          </dependentAssembly>
          <dependentAssembly>
            <assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
            <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
          </dependentAssembly>
          <dependentAssembly>
            <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
            <bindingRedirect oldVersion="1.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
          </dependentAssembly>
        </assemblyBinding>
      </runtime>
      <entityFramework>
        <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
        <providers>
          <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
        </providers>
      </entityFramework>
      <!-- http://www.asp.net/identity/overview/features-api/best-practices-for-deploying-passwords-and-other-sensitive-data-to-aspnet-and-azure        -->
      <!--                                                                                                                                              -->
      <!-- The configsource attribute replaces the entire <connectionstrings> markup  Thus it doesnt leave any room for merging with existing           -->
      <!-- attributes in the connectionstring element The external connection strings file must be in the same directory as the root web.config         -->
      <!-- file so provisions must be in place to ensure you dont check it into your source repository                                                  -->
      <!--                                                                                                                                              -->
      <!-- Using the configsource attribute as shown below prevents visual studio from detecting that the project is using a database when creating     -->
      <!-- a new web site and thus you wont get the option of configuring the database when you publishing to azure from visual studio                  -->
      <!--                                                                                                                                              -->
      <!-- <connectionStrings><add name="PetTrackerContext" connectionString="provider connection string=&quot;user id=SQLDBUSER;password=PASSWORD;data source=pettracker2016.database.windows.net;initial catalog=PetTracker;persist security info=True;MultipleActiveResultSets=True;App=EntityFramework&quot;;metadata=res://*/Models.PetTrackerModel.csdl|res://*/Models.PetTrackerModel.ssdl|res://*/Models.PetTrackerModel.msl;provider=System.Data.SqlClient;" providerName="System.Data.EntityClient" /></connectionStrings> -->
      <connectionStrings configSource="ConnectionStrings.config">
      </connectionStrings>
      <system.codedom>
        <compilers>
          <compiler language="c#;cs;csharp" extension=".cs" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:6 /nowarn:1659;1699;1701" />
          <compiler language="vb;vbs;visualbasic;vbscript" extension=".vb" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:14 /nowarn:41008 /define:_MYTYPE=\&quot;Web\&quot; /optionInfer+" />
        </compilers>
      </system.codedom>
    </configuration>

我尝试在阳光下使用几乎任何我可以掌握的方法来丰富 Startup.cs 文件,以便正确加载 index.html(顺便说一句,我没有在 html5 模式下使用 angular)。然而,即使在启动服务器时显示 index.html,所有其他资源(.css、.js 文件)也无法加载,并在开发者工具的控制台中显示垃圾邮件“404 Resources not found”浏览器。我尝试过的一些事情:

How to set default static web page for Katana/Owin self hosted app?

https://docs.asp.net/en/latest/fundamentals/static-files.html

How to intercept 404 using Owin middleware

到目前为止,我尝试过的任何方法都没有奏效。那么如何才能使 index.html 在 OWIN 下正确加载(使用 .js/.css 资源和所有资源)?任何干净地解决此问题的代码 sn-ps 将受到高度赞赏。提前感谢,如果我错过了一些明显的东西,我们深表歉意。

【问题讨论】:

    标签: asp.net angularjs visual-studio owin


    【解决方案1】:

    默认情况下,作为一种安全机制,IIS 会阻止对“bin”文件夹的访问,否则可能会有恶意行为者下载已编译的站点 DLL。

    如果你真的想允许它,你需要通过将以下内容添加到 web.config 从过滤路径列表中删除“bin”:

    <?xml version="1.0"?>
    <configuration>
       <system.webServer>
           <security>
              <requestFiltering>
                   <hiddenSegments>
                       <remove segment="bin" />
                   </hiddenSegments>
               </requestFiltering>
           </security>
       </system.webServer>
    </configuration>
    

    见:http://weblogs.asp.net/owscott/iis7-blocks-viewing-access-to-files-in-bin-and-other-asp-net-folders

    我会提醒您不要使用这种方法,因为它确实会影响安全性,并且只会将您的 SPA 文件夹/文件放在网站的根目录中,而将您编译的资源放入 bin 子文件夹中。

    【讨论】:

    • 感谢您的提示。我试了一下,但仍然不高兴:(我是否必须对 startup.cs 进行任何特殊更改才能使其正常工作?
    • 我通过 Visual Studio Community Edition 2015 使用最新最好的 IIS10.0 Express 顺便说一句(如果有什么不同的话)。
    • 我克隆了你的 GitHub 存储库,将 PetTrackerOAuth.Web 项目中的所有文件(web.config 除外)移到了 AngularJSAuthentication.API 项目中(并删除了所有文件上的复制到输出文件夹标志) .该站点出现并且所有 SPA 文件都可以正常加载:imgur.com/msR7HOs
    • 我还添加了我在回答中提到的 web.config 设置,并将其中一个 .js 文件手动复制到 bin 文件夹中,并且能够正确地将其拉起。 imgur.com/vn6BVFK
    • 感谢大卫的努力。我试过你的方法,它确实有效。我猜想在幕后发生了某种魔术,从某种意义上说,如果 .css/.js/.whatever 文件没有明确列在 ASP 的 .csproj 文件中。 NET 项目,则该文件被认为是可以移交 http 的资源(即使所述文件已以某种方式复制并因此 物理存在在 /bin 目录中)。可以将 OWIN 调整为不仅仅是 index.html 的静态文件 http-server 吗? (这样我就可以将两个项目分开)。再次感谢。
    猜你喜欢
    • 2013-09-14
    • 2015-05-17
    • 2021-05-11
    • 1970-01-01
    • 2016-06-26
    • 2018-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多