起初的几点思考
- 原始的jquery项目是没有工程化可言的,单独把原本项目改成单页应用等于回炉重造
- jquery项目之间的重复页面很难有像现在vue,react等组件哪样的开发体验,只有iframe标签,object标签,或者get请求其文本文件镶嵌到当前页面($.load等)
- 如果需要改造,要重新做工程化?上webpack?no no no 十几个配置项都不够整的,时间成本不值当,想想 项目最终还是在nginx上部署的,我能否用最简单的方式改造?
- 还有一点html文件量很大 大概120个文件,有些是独立的,有些是相互嵌套的,资源都是独立引用的。
- 所以下面我采用最直接了当的方式,不改动源码,用nginx做请求处理,也作为开发和发布的容器来改造原始项目
文件结构
其实整体就是一个nginx,cmcs_html就是前端文件
项目启动:双击start.bat就行 linux的命令自己看常用命令自己手动启动或者做个启动脚本哈
停止nginx服务:双击stop-all.bat 注意 是停止所有的nginx项目
项目配置文件:conf/self/index.conf 在这里配置端口 以及访问规则
拆分流程
下面的拆分流程按照重要程度来码的,实际操作过程要按照倒序来~
下面环境说明:
原始项目端口:http://localhost:8080/cmcs/index
改造后的前端项目端口:http://localhost:3000/index
项目是一个桌面级的web应用
接下来分析了
我们的目标是把所有的请求按照一定的规则,在nginx中做请求处理,我们需要做的是把请求分类
上诉请求分为三大类
静态资源 .js .css.png等 项目素材
html 文档类型文件 请求的前端页面
xhr 请求后端获取数据的接口
拆分过程
在强调一遍~我们整体目标是把所有的请求通过nginx转发到服务器或者本地(静态资源)
代码中的需要处理的三块,不同的项目 根据场景来
-
这个项目通过后端控制路由的,Ajax的请求与html页面跳转在拦截规则的时候无法过滤,怎么做区分呢?(具体看上面的原始的环境的图) 比如请求/index 和访问/login 怎么区分 index是访问index.html login是登陆操作
1.1 ajax的跳转的cookie怎么携带?
1.2 当前项目在登陆失败后后端是直接sendRedirect 转发到/login怎么才能集中做请求拦截?
-
代码中的Html的页面跳转
2.1 前端代码中通过loadPage方法请求,可以当做成ifream设置src请求后端(原代码是解析成Object标签 加data属性的形式),怎么让它直接请求前端根目录下的html文件呢?
2.2 页面之间的跳转,处理的映射关系src\main\java\com\cmcc\cmdi\controller\PageController.java做的文件映射关系 有些是比如首页有两个index2.html和index1.html 在这个文件可以得到应证
-
原始项目后台路径转发有携带参数
3.1 大部分页面有带有省份的参数provinceName 这个是存在session中 如果分离 怎么获取?
静态目录的问题
4.1 如下图所示html的js和图片和字体图标都储存在static目录下的 如果不做特殊处理想引用对,那么要把static全部搬到根目录下,那么js和html和png都炸锅了~
可以看到大致的资源引入方式,和文件的分布
解决方案
问题1.1~1.3Ajax的请求与html页面跳转在拦截规则的时候无法过滤 cookie的问题 登陆拦截的问题
思路:页面上所有的请求大部分都是jquery的$.ajax方法发送的,我要做的是重写ajax 在发送请求的时候在url上面拼接/api/路径 有固定的前缀 nginx方便做规则
实现:
- 重写的脚本放哪里合适?当然放到jquery后面,每一个文件都加太麻烦,看了下项目中大部分html都引入了<script src="js/util/util.js"></script> 脚本 为了减少工作量把重写ajax的方法写在尾部,在每个html中引入
<!--错误 后引入的jquery会覆盖$.ajax方法-->
<script src="jquery.js"></script>
<script src="js/util/util.js"></script>
<script src="jquery.js"></script>
<!--正确-->
<script src="jquery.js"></script>
<script src="js/util/util.js"></script>
- cookie的携带问题?nginx配置转发完事~
proxy_cookie_path $path /;
- 登陆拦截怎么处理?原本项目中java的登陆拦截是在LogHandlerInterceptor.java中转发到\login但是由于 后端面项目加了项目名的原因 导致重定向给niginx的结果为http://localhost:3000/cmcs/login 单独去做拦截转发也有可能造成永久重定向的问题 所以 这里解决方案需要后端配合,当登陆失效的时候 返回的response.status的状态码为1002就行 返回不用给数据撒的,直接判断状态码后直接跳转到登陆页面,下图中的util.js中的180行代码,跳转login然后被niginx拦截会加上.html
解释下niginx配置
后端地址 http://localhost:8080/cmcs/loginVertify
前端请求地址: http://localhost:3000/api/loginVertify
nginx的配置作用:
- 拦截api
- 加上项目名
- $path设置
- 去除/api/
- 代理和cookie的path -这里是因为原本项目带项目名转发的cookie的path /cmcs 所以要去除path cookie的path特性是当前路径下的所有请求才会带上cookie
cookie:/cmcs ---> /
url:http://localhost:3000/api/loginVertify ----> http://localhost:8080/cmcs/loginVertify
问题2.1请求ajax的url处理了那么请求静态文件的呢?就是一个抄底的做法,
思路:前端代码中通过loadPage方法请求,可以当做成ifream设置src请求后端(原代码是解析成Object标签 加data属性的形式),怎么让它直接请求前端容器根目录下的html文件呢?
实现: 下面的请求地址,在原始项目中都是请求后端的PageController.java处理的映射关系,需要吧请求的地址 直接请求到前端项目容器的html文件,只需要加后缀就行了
htmlName ----> htmlName.html
其实这里没有任何的规则项 直接配置一个兜底的配置就行
问题2.2页面之间的跳转,处理的映射关系
思路:上诉的配置 已经可以把所有的html文件正常访问了,接下来只是改文件和应证的工作
实现:下面拿index1.html index2.html举例
如果看到页面上有两个相识的文件 什么12结尾的,什么old 什么cp 都去pageController里面去看下是否是注释掉的, 返回的字符串如果是index2那么index2.html是项目正在使用的页面
把不要的html的页面 移动到delete/文件加目录下
把index2.html改成index.html
代码含义
如果请求 /index 返回的是template/index2.html文件
如果请求 /indexnew 返回的是template/index.html文件
Indexold被注释掉了 就删掉吧
问题3原始项目后台路径转发有携带参数
思路:多页面传参provinceName的解决方案基本上大部分页面都有这个参数还有一些页面有其他参数,用混入模式的方式 尽量保证不动原有代码 如果改动小可以根据原本的代码获取方式变动,在unit.js里面全局统一改动
实现:先了解原始的传参过程和获取参数的方式。在登陆的时候获取省份保存在localStorage里面每个页面加载util.js在适当的时候赋值上去,保证原始代码在获取的时候不出问题 如果出现选择器的影响可以判断下当前ifream的url来区分
如果有其他其他参数 手法一样,这里全局配置通过url判断一下
如何赋值呢?在util里面全局处理,如果怕其他页面造成选择器的污染 加url(这个url是当前ifream的url ) 做判断
赋什么值?答~看原始系统
数据哪里来?
坐等后端改登陆接口,注意加rlpt_的前缀的原因是防止本地缓存的变量名冲突 因为localStorage没有path
到此项目已经拆分完毕!!!
关键文件
nginx 配置文件
server {
listen 3000;
server_name localhost;
#本地
set $baseUrl "http://127.0.0.1:8080";
#测试
#set $baseUrl "http://192.168.110.240:8080";
#发布
#set $baseUrl "http://127.0.0.1:8080";
#路径 后台项目名或者多出来的请求路径 不要以/结尾 原本的项目的cookie path是没有/的
set $path "/cmcs";
#根目录
set $baseRoot "cmcs_html";
gzip on; #启动
gzip_buffers 32 4K;
gzip_comp_level 6; #压缩级别,1-10,数字越大压缩的越好
gzip_min_length 100; #不压缩临界值,大于100的才压缩,一般不用改
gzip_types application/javascript text/css text/xml;
gzip_disable "MSIE [1-6]\."; # IE6对Gzip不友好,对Gzip
gzip_vary on;
#编码
charset utf-8;
#静态目录
root $baseRoot;
#传输大小
client_max_body_size 100M;
#----api拦截---- ajax会重写 在前面拼接api路径
location ~^/api(.*) {
#转发的时候服务地址的配置 加上了端口
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cookie_path $path /;
rewrite ^/api(.*) $path$1 break;
proxy_pass $baseUrl;
}
#static文件下的静态文件的地址拼接
#$1为上面匹配的正则表达式如果访问 /a/index.css--->static/a/index.css
location ~(.*\.(css|js|swf|jpg|gif|png|jpep|jpg|mp3|xx|xmlbak|xml|ttf|woff2|woff)) {
alias $baseRoot/static/$1;
}
#html页面
location ~(.*\.(html|htm)) {
alias $baseRoot/$1;
}
#访问所有 html文件名(htmlName) 重定向到htmlName.html
location ~(.*) {
if ( $request_uri = /) {
rewrite (.*) /index.html break;
}
rewrite (.*) $1.html break;
}
#----其他文件 正常情况不会出现----
location / {
return 888 "未捕获的路径,请重新配置nginx";
}
}
util.js
/*******************************************重写jaquery的ajax*****************************************************************/
/**
* 目的前后端分离的情况下
* 请求 index login 分不清是请求页面还是请求连接 nginx已经配置 会去请求 index.html和login.htm
*
* 如果想让login请求对应的后台服务器而不是前端页面需要加上api特定的前缀 已做区分
*
* 登陆失效:返回状态码为1002即可重定向到首页
*
* 完整的拆分方案 请阅读本项目根目录下的 "项目说明".doc文件
*/
(function () {
//避免jquery没引用报错
if (!$) return;
//ajax重写
(function ($) {
//保留原始ajax
let _ajax = $.ajax;
//重写
let ajax = function (url, option) {
//参数处理
let opts = url || {};
if (typeof url == "string") {
option.url = url;
opts = option;
}
//api路径拼接
opts.url = "/api/" + opts.url;
let complete = opts.complete;
opts.complete = function (res) {
//全局处理登陆失效
if (res.status == 1002) window.location.href = "login";
complete && complete.call(complete, res);
};
//调用
return _ajax.apply($, arguments);
};
//赋值
$.ajax = ajax;
})(jQuery);
//改造参数 多页面传参provinceName的解决方案 基本上大部分页面都有这个参数 还有一些页面有其他参数 不改动原始代码的情况下 在里面全局改动
//原理 在登陆的时候获取省份保存在localStorage里面 每个页面加载util.js在适当的时候赋值上去 如果出现选择器的影响 可以判断下当前ifream的url来区分
//其他参数 手法一样,这里全局配置 通过url判断一下 混入模式的方式 尽量保证不动原有代码 如果改动小可以根据原本的代码获取方式变动
//参数改造
$(() => {
$("#provinceName").val(localStorage.getItem("rlpt_provinceName"));
});
})();
完成页面
待完成问题
需要后端协调的地方
登陆拦截sdwy_sx\src\main\java\com\cmcc\cmdi\interceptor\LogHandlerInterceptor.java 返回response.status=1002 一个标记 让前端做跳转就行
页面间的跳转映射关系 可以不用管,前端不会受影响 毕竟是两个容器了,但是别删 方便核对
因为provinceName是在session中拿的,不是同一个项目拿不到,在登陆的时候给就行。形式也可以选其他的。接口格式
{
"status": 1,//1 登陆成功 //2登陆失败
"userInfo": {
"provinceName": "北京市"
}
}
- 报错处理,确认下后端代码报错后配置的页面是error下面的404.html和500.html,如果需要处理 需要后端在后台拦截所有的异常信息返回给前端对应的status 可以像方案1一样 1003 1004 对应的显示404和500页面
后续前端工作
主要是看其他界面功能是否正常
全局的util.js所有的页面已经加了(花了30分钟差不多,一百多个页面每个还只是加个js引用...不敢想想单个改难度会有多大)
有些后台页面跳转有其他参数传递需要后面跟进
文件上传是否也OK
这个肯定有问题,bootstarpTable自身的url做请求 这里它会用bootstarpTable插件内部的ajax 登陆失效并不会拦截 这个需要定位文件,方案是bootstarpTable的默认属性去覆盖它。后续优化,问题不大 大部分的bootstarpTable 是以data赋值塞数据的形式写的。
测试过的只有首页和登陆页面,看见其他页面很多接口报错~需要前后端联调报错接口,如果调试不知道是否是nginx的问题,那么请对照原始项目对应页面看是否也有问题来判断