前后端分离之SPA与跨域访问

引言

最近在开发一个以医院业务为背景的Web项目,前端采用React+Ant Design,后端采用SSM(Spring-SpringMVC-MyBatis)框架。由于就我和另外一名同学开发,我负责前端,他负责后端,两者分开独立完成,部署均在各自电脑的IP:Port上,所以在调试阶段如果想要追求开发效率,就必须攻克前后端工程分离所带来的两个问题:跨域访问、状态保存。然而前后端分离的这种架构,其实不仅是在调试阶段带来了便利,在后期部署做负载均衡等方面也颇具优势。而随之诞生的SPA(Single Page Application)即单页面应用正好适合这种分离架构的需要。下面我们详细探讨下。

前后端分离

传统的前后端混合的形式,是把页面、图片、样式、js这些属于前端的静态文件,以及src目录下编译好的.class、xml这些属于后端的文件统一放在webapp下,然后启动Web服务器即可在同一IP:Port下访问页面与api服务,如下图所示。



这种方式将静态与动态文件混合,经常是前端要进行页面跳转了,请求后端给返回所需的页面,比如返回JSP页面,而JSP实质是一个Servlet,在它返回前端之前,实质是先将获取到的数据渲染在了html页面上,最后再一并返回前端的。而事实上,JSP所做的渲染工作更适合前端来负责,后端只负责提供接口、处理逻辑、存取数据、返回所需JSON数据,即只应涉及到MVC模式中的Modal与Controller。
而前后端分离模式正好相反,它将前端的所有静态文件与后端的所有动态文件分别置于不同的IP或不同的Port(只要Port不同就会造成跨域)下,前端若要访问后端的服务,只要指定后端的IP:Port与api的URL即可访问到,职责很明确,如下图所示。



前后端分离带来的好处是明显的:
  • 服务器压力减小到最小,所有数据到页面的渲染工作可由前端js完成,摆脱业务逻辑与呈现逻辑在Java模版引擎中的耦合与混乱
  • 前端与后端可同时开发,前后端完全去耦,不再需要等待后端返回页面,效率显著提升
  • 多终端应用中接口统一,后端由于仅负责提供api接口,所以与前端彻底划清界限,前端的变化不会对后端造成任何影响,即后端不需为前端平台的任何改变而做出改变,前端是采用浏览器?还是移动设备?后端都只是提供统一的接口服务。但这也就意味着终端如果采用浏览器,其内置的一些状态机制如cookie、session最好不要使用,因为一方面跨域会造成cookie的sessionId失效,另一方面就算不失效,后端也无法与不支持这种状态机制的移动终端相适应,势必造成实现两套服务。
  • 按需加载提高用户体验,后端不再需要解析页面,前端的路由配置、模块化引入等功能可提升交互速度

SPA

前后端分离的同时也意味着前端页面需要肩负更加艰巨的任务,比如渲染页面与路由系统。因为后端不再提供页面了,所以转而交给了前端。然而前端具有动态特性东西的也就只有js了,无论交互逻辑还是路由,都要靠他来实现。
目前很流行的SPA单页面应用颠覆了传统的多页面交互,如下图所示:



当我们需要跳转页面的时候,并不是真的去访问一个全新的html页面,而是用js动态去替换之前的页面元素(比如传统的jQuery操作dom元素、React中的JSX数据状态渲染),同时改变浏览器链接处的锚点,实现前端对URL的完全掌控(React生态圈中react-router提供了很好的支持)。SPA无需任何模板去控制输入,其展现全部依靠js,目前主流前端框架Angular、React、Vue、Backbone均提供了对SPA很好的支持,可以说他们的技术出发点就是SPA。显然,这种交互方式避免了页面刷新,提供了更好的性能与用户体验。

跨域访问

这个好说,直接在后端加个拦截器,在里面对HTTP响应报文的header设置跨域允许即可,如下代码所示:

public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
        throws IOException, ServletException {
    HttpServletResponse response = (HttpServletResponse) servletResponse;
    response.setHeader("Access-Control-Allow-Origin", "*");
    response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT");
    response.setHeader("Access-Control-Allow-Headers", "x-requested-with, Content-Type, Accept, TOKEN, Content-Range, Content-Disposition, Content-Description");
    response.setHeader("Access-Control-Max-Age", "3600");
    filterChain.doFilter(servletRequest, servletResponse); 
}

再记得向web.xml文件中加入拦截器相关配置:

<filter>
    <filter-name>crossOriginFilter</filter-name>
    <filter-class>com.yhch.interceptor.CrossOriginInterceptor</filter-class>
</filter>
<filter-mapping>
    <filter-name>crossOriginFilter</filter-name>
    <url-pattern>/api/*</url-pattern>
</filter-mapping>

前端在采用AJAX访问时需要带上contentType字段,否则会报异常。示例代码如下:

$.ajax({
   url : SERVER_ADDRESS + '/api/user',
   type : 'POST',
   contentType: 'application/json',
   data : JSON.stringify({userName : 'ken'}),
   dataType : 'json',
   beforeSend: (request) => request.setRequestHeader(SESSION.TOKEN, sessionStorage.getItem(SESSION.TOKEN)),
   success : (result) => {...}
});

结语

说了那么多前后端分离的好,我们也要看到他的不好之处:

  • 开发单页面应用时,前端Route与服务器端Route不匹配
  • 重要内容都在前端组装,不利于SEO(搜索引擎优化)
  • 模板语言不相通

总之整体看来,个人感觉前后端分离还是利大于弊,特别是开发效率、后端统一提供接口、无状态性这几个优点很是优雅。本章提到过,前后端分离势必会造成跨域访问,虽然本章介绍了如何在后端设置header允许跨域访问,但跨域带来的麻烦仍未完全解决,其中一个就是cookie无法共享,导致后端无法高效记录前端的状态(如登录状态、购物车等)。接下来会写一篇讲述如何去维持前后端的状态。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容