react-router-dom和本地服务本地开发 (node、webpack)

场景

使用react 做开发,避免会使用react-router

React Router 已经是V4的版本

React Router 目前已经被划分成了三个包:react-routerreact-router-dom, react-router-native
React Router 应用提供了核心的路由组件和函数,另外两个包提供了特定环境的组件(浏览器和 react-native 对应的平台),不过他们也是将 react-router 导出的模块再次导出。

本文核心要讲的就是react-router-dom 和 本地服务的故事


react-router-dom作为浏览器的平台,是我们的做WEB首选。react-router-dom可以选择 <BrowserRouter><HashRouter> 组件

<BrowserRouter> 应该用在服务器处理动态请求的项目中(知道如何处理任意的URI)
<HashRouter> 用来处理静态页面(只能响应请求已知文件的请求)。

假如有一个 Link 标签,点击后跳转到 /test/guide。

BrowserRouter: http://localhost:8080/test/guide
HashRouter: http://localhost:8080/#/test/guide

通常来说更推荐使用 ,可是如果服务器只处理静态页面的请求,那么使用 也是一个足够的解决方案。

关于本地服务

现如今,前端开发避免不了本地服务开发,大多数会选择node做本地服务开发层,其中包括了koa,express。webpack做本地服务webpack-dev-server(也是一个express的服务)
有本地服务就避免不了本地路由。本地服务的get URL请求如何和react-router做适配呢?请往下看。

关于HashRouter 和本地服务

HashRouter做本地开发,主要是 hash 地址,hash 地址就是指 # 号后面的 url。这个功能只会实现静态页面的跳转,不会产生路由的变化
如上面例子HashRouter: http://localhost:8080/#/test/guide,对于服务端而言,路由实际还是再根目录下'/' ,而“#/test/guide” 只是hash地址,可以通过浏览器location 命令查看
因为对于服务端而言,路由实际上没有发生GET请求变化,以至于服务端不会发生响应,也不会存在Cannot GET页面提示404等问题。

其中如果是webpack服务,关于设置historyApiFallback:true 网上有很多的文章,给了这个答案,来处理本地服务问题

首先 devServer.historyApiFallback 用来应对返回404页面时定向到特定页面用的

如果你在webpack配置文件中修改了 output.publicPath 值默认为'/',那么你就需要声明请求重定向,配置historyApiFallback.index 值。

// output.publicPath: '/assets/'
historyApiFallback: {
 index: '/assets/'
}

关于BrowserRouter 和本地服务
由上面的例子BrowserRouter: http://localhost:8080/test/guide,可见,使用BrowserRouter,history对url链接进行了处理,当链接跳转之后,如果对页面进行刷新reload操作,那么本地服务
就会捕获到路由的GET请求,这就是问题的关键,需要本地服务对请求进行处理,方式有很多,这里介绍一种比较笼统直接的方式;

const router = express.Router();
const request = require("request-promise").defaults({ jar: true });

router.all("*", async (req, res, next) => {
	let url = req.url; //页面链接上的url
	let html = "";

	// 不匹配以下路由规则,只匹配URL GET请求
	if (url.match(/\.(png|jpe?g|gif|js|css|html|ico)/)) {
		return next();
	}

  	html = await reactRoute().catch(e => {
      //do error handle
      return false;
    });

  	if(html){
  		return res.send(html);
  	}

    //其他路由处理规则...
    return next();
})


async function reactRoute() {
  return new Promise((resolve, reject) => {

  	//这里可以做一层非react项目的过滤,这里不重要
  	// if(noReact){
  	// 	reject('no react url')
  	// }

    let html = await request({
      method: "get",
      url: `http://localhost:8080/pages/index.html`	//本地服务index路径(为react配置的BrowserRouter路径),因项目而异,只是一个例子
    }).catch(e => {
      reject(e);
    });

    resolve(html);
  })
}

以上代码的逻辑是,本地服务,读取URL get请求,如果本地服务请求404,那么把react 的BrowserRouter 启动文件返回,该文件应该是本地服务可以读取到的html文件。
以下是图解

posted @ 2018-08-28 20:41  _枪枪  阅读(924)  评论(0编辑  收藏  举报