8

我有一個快遞服務器,處理:1 API路由並呈現我的初始index.html包含bundle.js持有我的React/React-Router/Redux應用程序。快遞狀態404與反應路由器

因爲它的立場,它在我的網頁上是不可能的404,因爲我有一個包羅萬象的:對的NoMatchreact-router

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

爲了工作,我需要發送一個404碼。

我的路線如下:

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

陣營路由器 - :x/:x/:y

什麼,我基本上是想實現的是,如果用戶曾經進入的網址: :x/:y/z/and/further然後返回一個404,除非他們已經去的是/api/test/:x/:y

問題:

  1. 如何匹配路由,不包括我的API路由,最好以可擴展的方式,返回適當的狀態碼?
  2. 對於這麼簡單的事情,在子域上設置這個有很大的開銷嗎?這是否會緩解這個問題?當應用程序增長時,我會遇到問題嗎?
+0

您可能還想看看react-project如何處理:https://github.com/ryanflorence/react-project/blob/v0.0.30/modules/PublicServerAPI.js#L103-L134 –

回答

4

看看反應路由器的服務器端渲染文檔: https://github.com/reactjs/react-router/blob/master/docs/guides/ServerRendering.md

解決方案:

  1. 將路線提取到單獨的文件並在快速應用程序中要求它
  2. 在快遞中添加中間件,使用match函數從react-router中檢查快遞中的網址。它應該在負責API路由的中間件之後編寫。
  3. 但如果是對請求的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') 
    } 
    }) 
}); 

如果任何路線改變,你不需要在快速應用程序上執行某些操作,因爲您對前端和後端使用相同的代碼。

+0

這是正確的。 –

+0

https://reacttraining.com/react-router/web/guides/server-rendering - 未來讀者的更新鏈接 – eselk

0

您需要將您的實際API路徑放在您的全部API之上,以便它們在它之前被拾取。

基本上,中間件首先定義優先於路由複雜性。

一旦將響應發送到客戶端,Express將停止處理中間件,除非出現錯誤或出於某種原因,手動調用next

您可以定義一個簡單的錯誤處理,像這樣:

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

routerexpressmiddleware所以,當你定義你的路由的順序是非常重要的。爲了分離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; 
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就會失敗。