te')); return $arr; } /* 遍历用户所有主题 * @param $uid 用户ID * @param int $page 页数 * @param int $pagesize 每页记录条数 * @param bool $desc 排序方式 TRUE降序 FALSE升序 * @param string $key 返回的数组用那一列的值作为 key * @param array $col 查询哪些列 */ function thread_tid_find_by_uid($uid, $page = 1, $pagesize = 1000, $desc = TRUE, $key = 'tid', $col = array()) { if (empty($uid)) return array(); $orderby = TRUE == $desc ? -1 : 1; $arr = thread_tid__find($cond = array('uid' => $uid), array('tid' => $orderby), $page, $pagesize, $key, $col); return $arr; } // 遍历栏目下tid 支持数组 $fid = array(1,2,3) function thread_tid_find_by_fid($fid, $page = 1, $pagesize = 1000, $desc = TRUE) { if (empty($fid)) return array(); $orderby = TRUE == $desc ? -1 : 1; $arr = thread_tid__find($cond = array('fid' => $fid), array('tid' => $orderby), $page, $pagesize, 'tid', array('tid', 'verify_date')); return $arr; } function thread_tid_delete($tid) { if (empty($tid)) return FALSE; $r = thread_tid__delete(array('tid' => $tid)); return $r; } function thread_tid_count() { $n = thread_tid__count(); return $n; } // 统计用户主题数 大数量下严谨使用非主键统计 function thread_uid_count($uid) { $n = thread_tid__count(array('uid' => $uid)); return $n; } // 统计栏目主题数 大数量下严谨使用非主键统计 function thread_fid_count($fid) { $n = thread_tid__count(array('fid' => $fid)); return $n; } ?>javascript - ASP.NET Core with React template returns index.html - Stack Overflow
最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - ASP.NET Core with React template returns index.html - Stack Overflow

programmeradmin4浏览0评论

I am learning full-stack web development with .NET Core and React, so I created an ASP.NET Core Web Application project with React template in Visual Studio 2019.

At some point I noticed that if I request a non-existing URL, I don’t get an error or 404 page as I would expect but rather the index.html as the response.

I want that my backend returns a 404 status code whenever a non-existing URL is called.

I tried to fix this by adding a React Switch tag around Route tags in App.js and added a ponent that is shown when the requested URL doesn’t match the defined routes:

import React, { Component } from 'react';
import { Route, Switch } from 'react-router';
import { Layout } from './ponents/Layout';
import { Home } from './ponents/Home';
import { FetchData } from './ponents/FetchData';
import { Counter } from './ponents/Counter';
import NoMatch from './ponents/NoMatch'; // <-- Added this

export default class App extends Component {
  static displayName = App.name;

  render () {
    return (
      <Layout>
        <Switch> // <-- Added this
          <Route exact path='/' ponent={Home} />
          <Route path='/counter' ponent={Counter} />
          <Route path='/fetch-data' ponent={FetchData} />
          <Route ponent={NoMatch} /> // <-- Added this
        </Switch> // <-- Added this
      </Layout>
    );
  }
}
import React from 'react';

export default function NoMatch() {
  return (
    <div>
      <h1>Error</h1>
      <h2>404</h2>
      <p>Page was not found</p>
    </div>
  );
}

But I think it is not a real solution to the problem since I later discovered that sending a request to a non-existing API via fetch function also returns index.html as a response. The project has an example ponent FetchData that has a constructor with fetch function. Replacing the example URL with a non-existing path reproduces the behavior:

constructor (props) {
  super(props);
  this.state = { forecasts: [], loading: true };

  fetch('api/nonexistingpath') // <-- Changed this URL
    .then(response => response.json())
    .then(data => {
      this.setState({ forecasts: data, loading: false });
    });
}

So, I thought that the problem is in the .NET Core backend. I went to the Startup file and tried to fix this behavior there, I noticed that when removing everything from the parentheses of this piece of code:

app.UseMvc(routes =>
{
  routes.MapRoute(
    name: "default",
    template: "{controller}/{action=Index}/{id?}");
});

doesn’t change the behavior of the program. However, if I remove this code entirely, the frontend will load, but the fetch function doesn’t return the data, it again returns the index.html. I tried to change the template, but it seems to me, that it has no effect on programs behavior.

I am really confused, am I getting something wrong? Wouldn’t it be the expected default behavior to return an error or 404 page when requesting a non-existing URL? I couldn’t find much on the internet either.

I found this answer, but it doesn’t give any references or explanation on why it is the default behavior.

I tried to use code from this answer, but it blocks everything that is not an API call. Can somebody help me?

Thank you in advance!

Update #1

Ok, after long attempts, I seem to have found the solution that works for me:

app.MapWhen(x => x.Request.Path.Value.StartsWith("/api"), builder =>
{
  app.UseMvc();
});

app.MapWhen(x => !x.Request.Path.Value.StartsWith("/api"), builder =>
{
  app.UseSpa(spa =>
  {
    spa.Options.SourcePath = "ClientApp";

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

I am learning full-stack web development with .NET Core and React, so I created an ASP.NET Core Web Application project with React template in Visual Studio 2019.

At some point I noticed that if I request a non-existing URL, I don’t get an error or 404 page as I would expect but rather the index.html as the response.

I want that my backend returns a 404 status code whenever a non-existing URL is called.

I tried to fix this by adding a React Switch tag around Route tags in App.js and added a ponent that is shown when the requested URL doesn’t match the defined routes:

import React, { Component } from 'react';
import { Route, Switch } from 'react-router';
import { Layout } from './ponents/Layout';
import { Home } from './ponents/Home';
import { FetchData } from './ponents/FetchData';
import { Counter } from './ponents/Counter';
import NoMatch from './ponents/NoMatch'; // <-- Added this

export default class App extends Component {
  static displayName = App.name;

  render () {
    return (
      <Layout>
        <Switch> // <-- Added this
          <Route exact path='/' ponent={Home} />
          <Route path='/counter' ponent={Counter} />
          <Route path='/fetch-data' ponent={FetchData} />
          <Route ponent={NoMatch} /> // <-- Added this
        </Switch> // <-- Added this
      </Layout>
    );
  }
}
import React from 'react';

export default function NoMatch() {
  return (
    <div>
      <h1>Error</h1>
      <h2>404</h2>
      <p>Page was not found</p>
    </div>
  );
}

But I think it is not a real solution to the problem since I later discovered that sending a request to a non-existing API via fetch function also returns index.html as a response. The project has an example ponent FetchData that has a constructor with fetch function. Replacing the example URL with a non-existing path reproduces the behavior:

constructor (props) {
  super(props);
  this.state = { forecasts: [], loading: true };

  fetch('api/nonexistingpath') // <-- Changed this URL
    .then(response => response.json())
    .then(data => {
      this.setState({ forecasts: data, loading: false });
    });
}

So, I thought that the problem is in the .NET Core backend. I went to the Startup file and tried to fix this behavior there, I noticed that when removing everything from the parentheses of this piece of code:

app.UseMvc(routes =>
{
  routes.MapRoute(
    name: "default",
    template: "{controller}/{action=Index}/{id?}");
});

doesn’t change the behavior of the program. However, if I remove this code entirely, the frontend will load, but the fetch function doesn’t return the data, it again returns the index.html. I tried to change the template, but it seems to me, that it has no effect on programs behavior.

I am really confused, am I getting something wrong? Wouldn’t it be the expected default behavior to return an error or 404 page when requesting a non-existing URL? I couldn’t find much on the internet either.

https://stackoverflow./a/53687522/10951989

I found this answer, but it doesn’t give any references or explanation on why it is the default behavior.

https://stackoverflow./a/44164728/10951989

I tried to use code from this answer, but it blocks everything that is not an API call. Can somebody help me?

Thank you in advance!

Update #1

Ok, after long attempts, I seem to have found the solution that works for me:

app.MapWhen(x => x.Request.Path.Value.StartsWith("/api"), builder =>
{
  app.UseMvc();
});

app.MapWhen(x => !x.Request.Path.Value.StartsWith("/api"), builder =>
{
  app.UseSpa(spa =>
  {
    spa.Options.SourcePath = "ClientApp";

    if (env.IsDevelopment())
    {
      spa.UseReactDevelopmentServer(npmScript: "start");
    }
  });
});
Share Improve this question edited Sep 9, 2019 at 11:34 AlexRekowski asked Sep 3, 2019 at 14:31 AlexRekowskiAlexRekowski 1932 silver badges12 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 14

The ASP.NET Core + React template creates a project that does two things at once:

  1. Acts as a web server to host the static files (your React app)
  2. Serves API responses (your C# controllers)

The behavior you're noticing (serving index.html instead of returning 404 for missing pages) is part of #1. Changing your React routing code didn't make a difference because it's server behavior. ASP.NET Core calls this a "SPA fallback route". This excellent blog post calls it "configurable static" behavior:

A web server can be configured to respond with an alternative file if the requested resource doesn’t actually exist on the disk. If a request for /bears es in and the server has no bears file, the configuration can tell it to respond with an index.html file instead.

The goal is to make it easier to have "pretty" URLs. If your React single-page app describes a route like /counter, but there is no counter.html on the server, then someone navigating directly to /counter from a bookmark or refreshing their browser will see a 404 error message. By configuring the server (ASP.NET Core in this case) to serve index.html instead of 404, the React app will be loaded and can respond correctly to the path in the URL.

If you ment out the app.UseSpaStaticFiles() line in your Startup class, your server should start returning real 404s. But that leaves the above problem with frontend routing.

Here's a snippet I use in my projects to serve index.html except when the request path starts with /api:

    app.UseMvc();

    app.MapWhen(x => !x.Request.Path.Value.StartsWith("/api"), builder =>
    {
        app.Run(async (context) =>
        {
            context.Response.ContentType = "text/html";
            context.Response.Headers[HeaderNames.CacheControl] = "no-store, no-cache, must-revalidate";
            await context.Response.SendFileAsync(Path.Combine(env.WebRootPath, "index.html"));
        });
    });
发布评论

评论列表(0)

  1. 暂无评论