0

I have an application that I've written using React/Redux on the front end with .NET Core 2.2 on the backend. It's your typical SPA app, I believe I started with CreateReactApp a long while ago. I've set up pages before with the routing working correctly, and when I would hit F5 on my keyboard or put the URL that should navigate to the page, everything would load as expected. You will see this in the example below, both the AuditLog and the AddLicenses pages load correctly on refresh or when I manually enter the URL (dev URL is ).

I'm developing a new feature on my application called Copy, and this new feature should have its own URL to resolve to (http://localhost:8080/Copy). However, for some reason, the URL won't actually load the page when I hit F5 and I get 405 error. This is the same if I manually copy and paste the URL into a new tab. However, if I select it from the navbar, it loads just fine. Here is the page when I select it in the navbar (I've removed some info as I'm not sure how much of the app I can share): FromNavbar

Here is the error I receive when I simply press F5 after navigating to that page from the navbar: On F5

Here is what my navmenu looks like:

import * as React from 'react';
import { Glyphicon, Nav, Navbar, NavItem } from 'react-bootstrap';
import { Container } from 'react-bootstrap/lib/Tab';
import { LinkContainer } from 'react-router-bootstrap';
import { Link } from 'react-router-dom';
import './NavMenu.css';


export default (props: any) => (
  <Container>
  <Navbar inverse={true} fixedTop={true} fluid={true} collapseOnSelect={true}>
    <Navbar.Header>
      <Navbar.Brand>
        <Link to={'/'}>App Name</Link>
      </Navbar.Brand>
      <Navbar.Toggle />
    </Navbar.Header>
    <Navbar.Collapse>
        <Nav>
        <LinkContainer to={'/Home'}>
          <NavItem>
              <Glyphicon glyph='home' /> Home
          </NavItem>
        </LinkContainer> 
        <LinkContainer to={'/AuditLog'}>
            <NavItem>
                <Glyphicon glyph='th-list' /> Audit Log
            </NavItem>
        </LinkContainer>
        <LinkContainer to={'/Copy'}>
            <NavItem>
              <Glyphicon glyph='glyphicon glyphicon-link' /> Copy
            </NavItem>
        </LinkContainer>
        {/* <LinkContainer to={'/AddLicenses'}>
             <NavItem>
                <Glyphicon glyph='apple' /> Add Licenses
            </NavItem>
        </LinkContainer>    */}
      </Nav>
    </Navbar.Collapse>
  </Navbar>
  </Container>
);

Also, here is my App.tsx file:

import { ImplicitCallback, Security } from '@okta/okta-react';
import * as React from 'react';
import { Route } from 'react-router';
import Layout from './components/Layout';
import AddLicenses from './components/Pages/AddLicenses';
import AuditLog from './components/Pages/AuditLog';
import Copy from './components/Pages/Copy';
import Home from './components/Pages/Home';

// Todo: Move OKTA configuration to its own file -- can be shared between client and server.
export const config = {
    client_id: 'REDACTED',
    issuer: 'REDACTED',
    redirect_uri: window.location.origin + '/implicit/callback'
  }

export default () => (
    <Layout>
        <Security issuer={config.issuer}
                  client_id={config.client_id}
                  redirect_uri={config.redirect_uri}
        >
            <Route path='/' exact={true} component={Home}/>
            <Route path='/Home' exact={true} component={Home}/>
            <Route path='/AddLicenses' component={AddLicenses} />
            <Route path='/AuditLog' component={AuditLog} />
            <Route path='/Copy' component={Copy} />
            <Route path='/implicit/callback' component={ImplicitCallback}/>
        </Security>
    </Layout>
);

If there is any more information that I can provide to clarify, I will be glad to do so. I've been stuck on this issue a little too long, and I'm the only dev working on this app, so any help would be appreciated!

COleson
  • 346
  • 3
  • 9

2 Answers2

0

The problem is this:

When you are in your SPA and you navigate to http://localhost:8080/Copy by, for example, clicking a button, the client side code handles the navigation (by messing around with the browser's address bar & internal history) and works as you expect.

When you directly enter that URL (or click refresh in the browser), the browser makes a request to http://localhost:8080/Copy which is handled by your server. Recall what refresh does: it instructs the browser to reach out to the URL in the address bar and reload everything from the server (possibly with some caching).

Thus, a refresh operation is not handled by your SPA and therefore the route cannot be handled.

The comments above from @MathieuK asking about server-side rendering are important because this is the main technique for handling this kind of issue: if the server is capable of responding to the routes that are defined in your SPA (by rendering the correct page on the server & sending it to the client), it will be able to handle arbitrary routes that are defined in your application.

An alternative way of handling this is to handle the click of the back or refresh button in your application instead of allowing the browser to do it. See this answer for a discussion. However, it has been my experience that different browsers handle this in different ways and this method can be tricky, so YMMV.

Kryten
  • 15,230
  • 6
  • 45
  • 68
  • Hello Kryten, I am curious about this, as all of the other pages that I have setup in the same way work, while this one seems to not. I can refresh these other pages and it will correctly reload the page as expected. Are you saying that I am incorrectly handlying the reload via my SPA? If so, where aside from the above two files am I missing this? If you could point me in the right direction, that would be great! – COleson Nov 18 '19 at 16:28
  • 1
    If it's working for old routes but not for the new route, my guess would be that whatever framework you're using was correctly set up for the old routes, but something is different in the new route you've just set up. You mention CreateReactApp (CRA) in your question, but CRA does not natively include any routing (you need to add other packages to do that). Without seeing the code, I couldn't guess what is different between old & new routes. – Kryten Nov 18 '19 at 18:20
  • Further to @Kryten's comment, there may be some restrictions set up that limit your SPA to certain predefined routes. Without seeing the whole codebase, I'd: 1) Ensure that e.g. `/AuditLog` is behaving how you want `/Copy` to work, 2) `grep` (or your search-through-entire-codebase method of choice) for `AuditLog` in your code and see if there are any files that list out specific routes. My expectation is that there's some kind of whitelisting going on. – Harry Vane Nov 18 '19 at 19:36
  • Thanks @Kryten. I am using React-Router to route these requests. – COleson Dec 02 '19 at 16:42
  • I have no idea why, but if I rename everything to Copy2, the routing then works on refresh. – COleson Dec 05 '19 at 17:28
0

I do not know why this issue is being resolved in this way, but I at least have found a way around this.

I knew that when I set up the routing on the server that this would route any request regardless if the page exists or not. If the page exists, it will route you to that page. If it does not exist, it will default to index.tsx. So the fact that I could input any URL except copy meant that something with that specific route would cause issues. I did a simple test and changed one value:

<Route path='/Copy' component={Copy} />

I changed this to

<Route path='/Copy2' component={Copy} />

By changing to /Copy2, the route now worked. I have no clue why. This route is being handled by the reactRouter, so something in there is not playing well with my route. So, instead of make this into an exploration, I am going to keep with the route with a 2 at the end of it.

COleson
  • 346
  • 3
  • 9
  • I had incorrectly set the server-side rendering in another spot and included a second attempt to render the same page. So the app was attempting to render the page in two places and this is what caused the error. – COleson Jan 09 '20 at 18:58