博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
react-router 踩坑记
阅读量:5100 次
发布时间:2019-06-13

本文共 3987 字,大约阅读时间需要 13 分钟。

react-router踩坑分享

背景

有一个Web项目,采用的是前后端分离的方式,前端使用的是react技术栈,后端使用的是Django框架。

有这么需求: 在一个新闻列表里,点击某一条新闻,要求新闻详情页里的title keywords description是动态的。

辛苦历程

JavaScript动态修改

当从后端取回数据时,用JavaScript动态改变title标签和meta标签就ok了。但是后来才发现,这个需求的目的是为了SEO,而爬虫可以爬到的数据是后端返回的html页面上的数据。如果是通过JavaScript来动态处理title keywords description的话,是不利于SEO的,因此,动态修改title keywords description只能放到后端做。后端将html拼接好,返回前端来,前端再进行相应的逻辑操作。

第一次尝试

当思路理清楚之后,其实想着也就很简单, 三步就可以了。

  1. 前端向后端发送请求。
  2. 后端获取前端发送请求的URL地址,得到参数,然后从数据库里读出相应的数据。
  3. 返回一个新的html页面。

然后开始进行测试:

首先,打开主页面,点击任意一条新闻,此时的url还是hash模式的。

1.png

当跳到新闻详情页表的时候,打开控制台,进入Network, 查看所发送的请求。

2.png

可以看见,请求的路径是localhost:3000, 也就是根目录,而后台配置的根路由的代码如下:

urlpatterns = [  url(r'^$', TemplateView.as_view(template_name='index.html'), name='index'),]

因此,可以知道,在请求后台的时候,后台返回了index.html模板回来。但是,问题出现了,我们想要返回的index.html里的keywords description title是在后端拼接好然后返回给前端,而目前我们所能实现的仅仅是返回一个index.html, 我们没办法改变那3个值,因为我们没有办法获取到前端的URL,或者说是前端没有办法传参数到后端去, 导致后端不能从数据库里查出来那三个值。

那么,现在需要解决的问题就是如何将参数传到后端去。

第二次尝试

由于,点击某条新闻的时候,跳到新闻详情页的时候,这是浏览器主动去向后端发送的请求,因此是很难去控制这个过程的。

所以,有了下面这个解决方案: 既然很难在浏览器主动发请求的时候去控制参数的传递,那么就不用去控制。而是在浏览器返回了index.html后,这个时候,已经有了新闻的id, 因此就可以人为的控制再发一次请求,这个时候后端配置一个路由,根据id去数据库里查找keywords description title, 并在后端拼接好返回给前端。只不过有个缺点,会刷新一次页面。

但是,在实践的过程中,我理论上推导了一次整个过程,当人为控制发请求后,后端返回一个index.html, 然后又会执行js文件,然后又会发请求,然后又会返回index.html, 然后又会执行js文件,然后又会发请求。。。 就这样,一直循环下去,显然是不可能的。

第三次尝试

这探索新的解决的方案的时候,了解了Http Header里的referer, 当浏览器向web服务器发送请求的时候,一般都会带上referer, 告诉服务器,我是从哪个连接来的。因为想着后端只要获取到了前端的URL,一切就搞定了,但是显而易见,referer依然不行。拿网易云音乐测试如下:

7.png

第四次尝试

在不断尝试的过程中,珩哥提到,后端获取不到前端的URL地址,是因为react-router路由是使用的hash路由(http://localhost:3001/#/news/index/4141?_k=mv8udy),如果将hashHistory改为browserHistory(http://localhost:3001/news/index/4141)的话,那么后端一定就可以获取到前端的URL。

解决方案:

cd projectName/app/srcvim app.js// hash路由import { Router, hashHistory as historyProvider, match } from 'react-router';// 修改为browserHistoryimport { Router, browserHistory as historyProvider, match } from 'react-router';

进行查看:

主页面:

3.png

新闻详情页:

4.png

总结步骤

  1. 设置react-router路由方式为: import { browserHistory } from 'react-router';
  2. 对服务器进行改造,否则用户直接请求某个某个路由,就会报404。
  3. 进行测试。

那么如何进行测试呢?

  1. 看前端的请求地址。
  2. 多刷新页面试试。(因为之前的是单页面的,就算改变了路由,还是不会向后台发送请求。)
  3. 多看title的变化, 会遗留title不变化或者说是变化出错的bug。
  4. 只要有处理路由相关的地方,都测一下。(很重要)

其他方案

不知道大家是否还有其他解决方案?

原理

History

是一个库,react-router基于它来管理历史会话记录。

简单的说,一个history知道如何去监听浏览器地址栏的变化,并解析这个URL转化为location对象,然后router使用它匹配到路由,最后正确地渲染对应的组件。

常见的3种History

BrowserHistory

它其实就是HTML5推出的历史记录API,可以把浏览器记录当作一个栈,通过History提供的API来对浏览器记录进行相应的操作。

常见的方法有下面这几种:

  1. history.push(path, [state])
  2. history.replace(path, [state])
  3. history.go(n)
  4. history.goBack()
  5. history.goForword()

BrowserHistory是使用react-router应用推荐的history。它使用浏览器中的API用于处理URL,会创建一个像example.com/some/path这样的真实的URL。

要使用这个History的话,必须在服务器端做好处理URL的准备。一般从下面几个方面来考虑:

  • 处理/的请求, Django简单配置如下:
// urls.pyfrom apps import viewsurlpatterns = [    url(r'^$', views.index, name='index'),]
  • 处理打开新页面的URL跳转,比如点击某条新闻,跳转到新闻详情页这样的URL跳转(即本文开头的介绍)。
  • 处理每个URL的路由, 这也是最容易被忽视的一部分。当你在导航栏里点来点去,显示是没有问题的,就像下面这样。
    5.png
    但是当你刷新页面的时候,你会得到这样一个结果:
    6.png
    这是由于,你的应用是单页的,当你点击导航栏的时候,页面并没有刷新,只是JavaScript去请求了后台,然后更新了前端路由和组件状态,但是没有刷新页面,导致没有去请求后台的地址。所以,必须为每个URL在后端配置路由。一般来说,只需要配置简单的根路由就可以了,除非你需要动态更改模板index.html上的数据。

HashHistory

Hash history使用URL中的hash(#)部分去创建形如: example.com/#/path的路由。

像?_k=ckuvip没用的URL是什么东西?
  1. 每个URL对应都会对应一个state对象,你可以在对象里存储数据(比如当前页面滚动到哪个位置了),但是这个数据不会出现在URL中。实际上,数据被存到了sessionStorage中。

  2. 当一个history通过应用程序的push或者replace作跳转时,它可以在新的location里存储location state, 而不用显示在URL中,它类似于一个HTML中的post的表单数据。

  3. 在DOM API中,这些hash history通过window.location.hash = newHash很简单地用于被跳转,且不用存储它们的location state。但我们想要每个history都能使用location.state, 因此要为每个location创建一个唯一的key, 并把它们的状态存储在sessionStorage中。当点击'后退'和'前进'时,我们就会有一个机制去恢复这些location state。

MemoryHistory

Memory history不会在地址栏里被操作或读取,这就解释了是如何实现服务端渲染的。

BrowserHistory与HashHistory的对比

实际上,两种History都只是人为控制路由的一种手段。

相同点:

它们都只是简单的改变了地址栏里的URL,如果没有刷新页面的话,都不会向后端主动发送请求。

不同点:

当页面刷新的时候,对于BrowserHistory, 浏览器会向后台发送整个URL的请求, 而对于HashHistory, 它只会请求后台的根目录。

使用场景

  1. 不能完全是单页应用。
  2. 必要要刷新页面,因为这样,才会有向后端发送请求。
  3. 需要动态改变模板里的内容,比如head里的内容。
  4. 不是特别复杂的系统。

其他

推荐阅读:

感觉单页的seo,除了用SSR,就没有其他的办法了。

参考

转载于:https://www.cnblogs.com/yzfdjzwl/p/7106792.html

你可能感兴趣的文章
HtmlUnitDriver 网页内容动态抓取
查看>>
ad logon hour
查看>>
获得进程可执行文件的路径: GetModuleFileNameEx, GetProcessImageFileName, QueryFullProcessImageName...
查看>>
证件照(1寸2寸)拍摄处理知识汇总
查看>>
罗马数字与阿拉伯数字转换
查看>>
Eclipse 反编译之 JadClipse
查看>>
asp.net 获取IP地理位置的几个主要接口
查看>>
Python入门-函数
查看>>
[HDU5727]Necklace(二分图最大匹配,枚举)
查看>>
距离公式汇总以及Python实现
查看>>
设计模式之装饰者模式
查看>>
一道不知道哪里来的容斥题
查看>>
Blender Python UV 学习
查看>>
window添加右键菜单
查看>>
入手腾龙SP AF90mm MACRO
查看>>
python学习4 常用内置模块
查看>>
Window7上搭建symfony开发环境(PEAR)
查看>>
ResolveUrl的用法
查看>>
Linux内核态、用户态简介与IntelCPU特权级别--Ring0-3
查看>>
第23月第24天 git命令 .git-credentials git rm --cached git stash clear
查看>>