使用react-router表达状态404

时间:2016-02-20 13:46:12

标签: javascript node.js express http-status-code-404 react-router

我有一个快速服务器处理:1个API路由并渲染我的初始index.html以包含bundle.js持有我的React / React-Router / Redux应用程序。

按照目前的情况,我的网页上不可能有404,因为我抓住了所有内容:

app.use(function (req, res) {
  return res.render('index')
})

为了使react-router NoMatch能够正常工作,我需要发送404代码。

我的路线如下:

快递 - /api/test/:x/:y

反应路由器 - :x/:x/:y

我实际上要实现的目标是,如果用户访问的网址为::x/:y/z/and/further,则返回404,除非他们所访问的内容为{{1 }}

问题:

  1. 如何匹配路线,不包括我的API路线,最好是以可扩展的方式,返回适当的状态代码?
  2. 对于这么简单的事情,在子域上设置它有很大的开销吗?这甚至会缓解这个问题吗?当应用程序增长时,我会遇到问题吗?

6 个答案:

答案 0 :(得分:6)

看一下react-router服务器端渲染文档: reacttraining.com/react-router/web/guides/server-rendering

解决方案:

  1. 将路线提取到单独的文件,并在明确的应用
  2. 中要求它
  3. 在快递应用中添加一个中间件,使用match中的react-router函数检查快递中的网址。它应该在负责API路由的中间件之后编写。
  4. 如果请求网址没有合适的路由,请回复404。
  5. 因此,中间件应该与此类似:

    // origin code from https://github.com/reactjs/react-router/blob/master/docs/guides/ServerRendering.md
    // this is ES6, but easily can be written on a ES5.
    
    import { match, RouterContext } from 'react-router'
    import routes from './routes' 
    
    var app = express();
    
    // ...
    
    app.use((req, res, next) => {
      match({ routes, location: req.url }, (error, redirectLocation, renderProps) => {
        if (error) {
          res.status(500).send(error.message)
        } else if (redirectLocation) {
          res.redirect(302, redirectLocation.pathname + redirectLocation.search)
        } else if (renderProps) {
             // You can also check renderProps.components or renderProps.routes for
            // your "not found" component or route respectively, and send a 404 as
            // below, if you're using a catch-all route.
    
            // Here you can prerender component or just send index.html 
            // For prependering see "renderToString(<RouterContext {...renderProps} />)"
            res.status(200).send(...)
        } else {
          res.status(404).send('Not found')
        }
      })
    });
    

    如果任何路线发生变化,您无需在快递应用上执行某些操作,因为您在前端和后端使用相同的代码。

答案 1 :(得分:0)

您需要将实际的API路线放在全部上方,以便在它们之前拾取它们。

基本上,首先定义的中间件优先于路由复杂性。

一旦响应被发送到客户端,Express将停止处理中间件,除非引发错误或由于某种原因,next被手动调用。

您可以定义一个简单的错误处理程序,如下所示:

app.use(function catchError(req, res, next, err) {
    console.error('Caught error', err);
    res.status(500).json({
        error: err
    });
});

答案 2 :(得分:0)

router中的expressmiddleware因此,在您定义路线时,顺序非常重要。为了分离API路由,您可以创建一个模块来处理这些路由,然后创建middlewares以捕获其他路由,包括404路由响应。别忘了先把api路线放好。这是一个例子:

var express = require('express');
...

var routes = require('./routes/api');
var app = express();
...

// handle the request for the API
app.use('/api', routes);
...

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// error handlers

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
  app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
      message: err.message,
      error: err
    });
  });
}

// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
  res.status(err.status || 500);
  res.render('error', {
    message: err.message,
    error: {}
  });
});


module.exports = app;

和api路由模块:

var express = require('express');
var router = express.Router();

/* GET test page. */
router.get('/test/:x/:y', function(req, res, next) {
  res.render('test', { x: req.params.x, y: req.params.y });
});

module.exports = router;

答案 3 :(得分:0)

听起来像你可以使用溃败的顺序对你有利。

app.get('/api/test/:x/:y', function(){})

app.get('/:x/:y', function(){})

app.get('/:x/:y/:err', function(res, req){ res.status(404).send('oops') })

这样,请求会尝试/api/test然后/something/something然后如果/something/something/something-else它将失败。

答案 4 :(得分:0)

我设法通过React Router v4来使我的React应用程序与运行类似于handle.bars的liquid.js的快速服务器一起工作,该解决方案对于任何其他模板引擎的工作方式都相同。

在您的React App.js中,确保已安装和设置React Router v4:

import React, { Component } from 'react';
import { TransitionGroup, CSSTransition } from "react-transition-group";
import 'foundation-sites';
import {
  BrowserRouter as Router,
  Route,
  Switch
} from "react-router-dom";
import './assets/css/foundation.min.css';
import './assets/css/settings.scss';
import './assets/css/structure.css';
import './assets/css/owl-slider.css';
import './assets/fonts/fontawesome/all.css'; 


// ## COMPONENTS
import Header from './components/Header/header';
import Footer from './components/Footer/footer';

// ## PAGES 
import HomePage from './components/Pages/Home/homePage';
import AboutPage from './components/Pages/About/aboutPage';
import ServicesPage from './components/Pages/Services/services';
import ContactPage from './components/Pages/Contact/contact';


class App extends Component {


  render() {
    return (
      <Router>
        <div className="App page-a blur" id="page" data-toggler=".blur" >
          <Header/>
          <div className="pageWrapper">
          <Route render={({ location }) => (
              <TransitionGroup>
                <CSSTransition key={location.key} classNames="pageTransition" timeout={500}>
                  <Switch location={location}>
                    <Route exact path="/" exact component={HomePage} />
                    <Route path="/services" render={props => <ServicesPage {...props}/>} />
                    <Route path="/about" component={AboutPage} />
                    <Route path="/contact" component={ContactPage} />
                    <Route render={() => <div>Not Found</div>} />
                  </Switch>
                </CSSTransition>
            </TransitionGroup>
          )}/>
          </div>
          <Footer footerMessage="Liliana Alves // Sport &amp; Soft Tissue Therapist"/>
        </div>
      </Router>
    );
  }
}

export default App;

上面的代码将确保当用户导航您的React应用并且路线正在执行工作时,将用户发送到他们手动导航,刷新或输入URL的页面。

在快速服务器app.js中,您想为react应用定义主访问根目录“ /”“请勿使用通配符*(星号),这将不起作用!” :

app.get('/', (req, res) => {

        res.status(200).sendFile(path.join(__dirname+'/react-site/build/index.html'));

}); //THE REQUEST CONTENT

然后,如果您的Express中有一个404,它将使用React Router将您的用户重定向回React以处理404,这是通过Express错误处理程序完成的:

app.use((req, res, next) => {
    const error = new Error('Not Found'); //Error object
    error.status = 404;

    //res.render('./404'); by default in express applications you would render a 404 page

    res.status(200).sendFile(path.join(__dirname+'/react-site/build/index.html'));

    next(error);

});

如果有人认为应该改进它,或者它可能需要更多有关错误功能的支持,我花了很多时间进行研究,以使其工作。

答案 5 :(得分:0)

对此我有一个更愚蠢但更简单的解决方案。我让我的应用在服务器端呈现任何 URL,如果不匹配 xs 将呈现我的 404 页面。我只是检查我的响应文本是否有任何 404 相关,例如选择器或其他东西。如果是这样,我将使用 404 标头发送该内容。

请注意这远不是一个好的解决方案,但它很便宜。