使用反应路由器表达状态 404
Express status 404 with 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
React 路由器 — :x/
、:x/:y
我基本上想要实现的是,如果用户曾经转到 URL 的::x/:y/z/and/further
然后 return 404,除非他们去的是/api/test/:x/:y
问题:
- 我如何匹配路由,排除我的 API 路由,最好以可扩展的方式,returning 适当的状态代码?
- 对于如此简单的事情,在子域上进行设置是否有很大的开销?这甚至可以缓解这个问题吗?当应用程序增长时,我会遇到问题吗?
您需要将实际的 API 路线放在您的 catch-all 之上,以便它们在它之前被拾取。
基本上,首先定义的中间件优先于路由复杂度。
一旦向客户端发送响应,Express 将停止处理中间件,除非抛出错误或出于某种原因手动调用 next
。
您可以像这样定义一个简单的错误处理程序:
app.use(function catchError(req, res, next, err) {
console.error('Caught error', err);
res.status(500).json({
error: err
});
});
express
中的 router
是 middleware
因此,在定义路由时顺序非常重要。为了分离 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;
查看 react-router 服务器端渲染文档:
reacttraining.com/react-router/web/guides/server-rendering
解决方案:
- 提取路由以分离文件并在 express 应用程序中要求它
- 在 express 应用程序中添加一个中间件,使用
react-router
中的 match
函数在 express 中检查 url。它应该写在负责 API 路由的中间件之后。
- 如果请求url没有合适的路由,则用 404 响应。
所以,中间件应该是这样的:
// 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')
}
})
});
如果任何路线发生变化,您无需在 Express 应用程序上执行任何操作,因为您在前端和后端使用相同的代码。
听起来你可以利用路线的顺序来发挥你的优势。
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
它将失败。
我设法让我的 React 应用程序与 React Router v4 一起使用 express 服务器 运行 liquid.js 类似于 handlebars 该解决方案对任何其他模板引擎的工作方式相同。
在你的 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 & Soft Tissue Therapist"/>
</div>
</Router>
);
}
}
export default App;
以上代码将确保当用户浏览您的 React 应用程序时,路由正在执行其工作,将用户发送到他们手动导航、刷新或输入 URL 的页面。
在你的 express server app.js 中,你想为你的 React 应用程序定义主访问根“/” "Do not use a wildcard * (asterisk) this will not work!" :
app.get('/', (req, res) => {
res.status(200).sendFile(path.join(__dirname+'/react-site/build/index.html'));
}); //THE REQUEST CONTENT
然后,如果您的 express 中有 404,它会将您的用户重定向回 React,以使用 React Router 处理 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);
});
我花了很多时间研究让它工作,如果有人认为这应该改进或者它可能需要更多的错误功能支持,请告诉我。
我有一个更愚蠢但更简单的解决方案。我让我的应用程序在服务器端呈现任何 URL,没有匹配项 react-router
将呈现我的 404 页面。我只是检查我的响应文本是否有任何 404 相关,比如选择器或其他东西。如果是,我将使用 404 header.
发送该内容
请注意,这远不是一个好的解决方案,但它很便宜。
我有一个快速服务器处理: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
React 路由器 — :x/
、:x/:y
我基本上想要实现的是,如果用户曾经转到 URL 的::x/:y/z/and/further
然后 return 404,除非他们去的是/api/test/:x/:y
问题:
- 我如何匹配路由,排除我的 API 路由,最好以可扩展的方式,returning 适当的状态代码?
- 对于如此简单的事情,在子域上进行设置是否有很大的开销?这甚至可以缓解这个问题吗?当应用程序增长时,我会遇到问题吗?
您需要将实际的 API 路线放在您的 catch-all 之上,以便它们在它之前被拾取。
基本上,首先定义的中间件优先于路由复杂度。
一旦向客户端发送响应,Express 将停止处理中间件,除非抛出错误或出于某种原因手动调用 next
。
您可以像这样定义一个简单的错误处理程序:
app.use(function catchError(req, res, next, err) {
console.error('Caught error', err);
res.status(500).json({
error: err
});
});
express
中的 router
是 middleware
因此,在定义路由时顺序非常重要。为了分离 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;
查看 react-router 服务器端渲染文档: reacttraining.com/react-router/web/guides/server-rendering
解决方案:
- 提取路由以分离文件并在 express 应用程序中要求它
- 在 express 应用程序中添加一个中间件,使用
react-router
中的match
函数在 express 中检查 url。它应该写在负责 API 路由的中间件之后。 - 如果请求url没有合适的路由,则用 404 响应。
所以,中间件应该是这样的:
// 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')
}
})
});
如果任何路线发生变化,您无需在 Express 应用程序上执行任何操作,因为您在前端和后端使用相同的代码。
听起来你可以利用路线的顺序来发挥你的优势。
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
它将失败。
我设法让我的 React 应用程序与 React Router v4 一起使用 express 服务器 运行 liquid.js 类似于 handlebars 该解决方案对任何其他模板引擎的工作方式相同。
在你的 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 & Soft Tissue Therapist"/>
</div>
</Router>
);
}
}
export default App;
以上代码将确保当用户浏览您的 React 应用程序时,路由正在执行其工作,将用户发送到他们手动导航、刷新或输入 URL 的页面。
在你的 express server app.js 中,你想为你的 React 应用程序定义主访问根“/” "Do not use a wildcard * (asterisk) this will not work!" :
app.get('/', (req, res) => {
res.status(200).sendFile(path.join(__dirname+'/react-site/build/index.html'));
}); //THE REQUEST CONTENT
然后,如果您的 express 中有 404,它会将您的用户重定向回 React,以使用 React Router 处理 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);
});
我花了很多时间研究让它工作,如果有人认为这应该改进或者它可能需要更多的错误功能支持,请告诉我。
我有一个更愚蠢但更简单的解决方案。我让我的应用程序在服务器端呈现任何 URL,没有匹配项 react-router
将呈现我的 404 页面。我只是检查我的响应文本是否有任何 404 相关,比如选择器或其他东西。如果是,我将使用 404 header.
请注意,这远不是一个好的解决方案,但它很便宜。