为什么需要前后端分离?
因为传统开发的后台开发中,后台工作者需要设计MVC三层,前后端都要懂一点,有点麻烦。
先看一下传统开发流程:
弊端:耦合度高,一旦出错不易找错
耦合度高导致维护性差,开发效率也低
扩展性差,无法兼容其他终端例如app
调试效率低
前后端分离后开发流程
观察可以发现:
前后端分离后,后台需要提供一个接口文档,开发相应的接口。
那接口文档是个什么东东呢?
接口文档:告诉前端:接口地址,参数是什么,分别是什么类型,返回值格式,每个key表示什么含义,下面有例子。
那么什么HTTP服务器(静态资源服务器)?它和tomcat服务器的区别是什么呢?
HTTP服务器就是只要能响应HTTP请求即可;
tomcat是servlet容器,可以处理HTTP请求,也能解析执行JSP+servlet
对比我们之前编写的整个项目结构和部署环境而言,有以下区别:
简言之,就是在传统开发上增加了一个服务器处理静态资源,将View和Controller层放到了前端,后台仅需处理数据存取相关及业务逻辑相关
前端:负责View和Controller层
后端:只负责Model层,业务处理/数据等。
前后端分离的优缺点
优点:
关注点分离,视图层和控制层逻辑移到了前端,后端更注重业务逻辑和系统构架
耦合大大降低,开发效率和维护效率都得到提高
错误友好,后台错误不影响前台界面展示
对于开发者,前后端不再需要过多的涉及彼此的开发语言
缺点:
前端开发者压力更大,需要关注Controller层
增加静态服务器后,系统结构更复杂
更多的HTTP请求,在移动端运行效率差
逻辑靠近前端,不同平台需针对性重复实现,(安卓iOS+web)
SEO优化无力,爬虫大多不支持ajax
爬虫一般只爬静态页面 xx.html
SEO(搜索引擎优化)搜索引擎本质上就是一个爬虫,seo优化本质就是对爬虫友好。
重新定义前后端
前后端分离 如何划分前端和后端?根据职责划分
前端负责V+C,后端负责 M和Service
前后端分离后,请求次数会变多
前后端分离页面执行流程(针对浏览器)
Controller层中会使用流程控制来完成数据校验,数据解析,页面的跳转等动作,那么如何完成呢,这就需要使用到JavaScript了
注意:如果前端是其他的例如iOS,安卓,则无需请求静态页面,页面的绘制是由系统原始语言实现的,只需要向后台请求json数据即可
那么一个前后端分离的项目,前端是如何完成最终的数据展示呢?上面已经提到,就是json
json
格式简单
解析方便,跨平台
轻量级
内容为字符串
Ajax
Ajax是客户端的一种请求方式,用于异步的向服务器发送HTTP请求并获取响应数据。
异步的好处在于,请求期间浏览器不会被卡死,可以正常响应用户操作
而常见的表单提交,和直接打开指定地址,都是同步的。
再次说一下接口文档:告诉前端:接口地址,参数是什么,分别是什么类型,返回值格式,每个key表示什么含义
下面书写一个简单的前后端分离
准备一个接口
package com.cx;
import java.io.IOException;
@javax.servlet.annotation.WebServlet(name = "jsonServlet",urlPatterns = "/jsonServlet")
public class jsonServlet extends javax.servlet.http.HttpServlet {
protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
doGet(request,response);
}
protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
//告诉客户端,返回值的类型是json
response.setContentType("application/json;charset=utf-8");
//返回的具体数据
response.getWriter().println("{\"name\":\"22我\",\"age\":18}");
}
}
编写静态页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="js/jquery-2.1.0.js"></script>
</head>
<body>
<h1>我是主页</h1>
<script>
$.ajax({
//请求的地址
url:"http://localhost:8080/qianHouDFL/jsonServlet",
//如果请求成功执行的代码
success:function (data) {
console.log(data);//data是服务器返回的数据
//将返回数据做成一个标签插入到页面中显示
document.body.insertAdjacentHTML("beforeend","<h1>%</h1>".replace("%",data.name));
document.body.insertAdjacentHTML("beforeend","<h1>%</h1>".replace("%",data.age));
},
//如果请求失败执行的代码
error:function (err) {
console.log(err);
}
});
</script>
哈哈哈
</body>
</html>
根据访问路径http://localhost:8080/qianHouDFL/mine.html得到运行结果
如果将.html拉到外面运行,例如HBuilder(别忘了导入依赖)则会发现页面上没有显示服务器返回的结果….
前后端分离之跨域问题
打开浏览器检查页面会发现没有输出服务器返回的消息而是,出现了一个错误信息,这就是前后端分离最常见的跨域问题
跨域就是一个页面的脚本访问了一个不属于当前服务器的资源
跨域是一个动词,描述的是浏览器在解析js时发现js代码请求了一个不属于当前服务器的资源,此时就是跨域访问
默认情况下,跨域访问是不被允许的,其本质是因为浏览器遵循了一个安全机制叫做同源策略
怎么判断是否同源?
ip(主机地址或域名) 端口号 请求协议
同源限制:
无法读取非同源网页的 Cookie、LocalStorage 和 IndexedDB
无法向非同源地址发送 AJAX 请求
什么时候产生跨域问题:
浏览器在解析执行一个网页时,如果页面中的js代码请求了另一个非同源的资源,则会产跨域问题
而浏览器直接跳转另一个非同源的地址时不会有跨域问题
解决跨域问题
既然禁止跨域问题是浏览器的行为,那么只需要设置浏览器允许解析跨域请求的数据即可,但是这个设置必须放在服务器端,由服务器端来判断对方是否可信任
在响应头中添加一个字段,告诉浏览器,某个服务器是可信的
package com.cx;
import java.io.IOException;
/**
*
*/
@javax.servlet.annotation.WebServlet(name = "jsonServlet",urlPatterns = "/jsonServlet")
public class jsonServlet extends javax.servlet.http.HttpServlet {
protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
doGet(request,response);
}
protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {
//告诉客户端,返回值的类型是json
response.setContentType("application/json;charset=utf-8");
//解决跨域问题,在响应头中明确指出,对方是可信的
//*表示 允许所有来源的跨域访问 (测试时用,正式部署需要指定为静态资源服务器地址)
response.setHeader("Access-Control-Allow-Origin","*");
//返回的具体数据
response.getWriter().println("{\"name\":\"22我\",\"age\":18}");
}
}
其值可以是某个或多个指定的域名,也可以是*表示信任所有地址
其他相关设置
//指定允许其他域名访问
‘Access-Control-Allow-Origin:http://XXX.XXX.XXX’//一般用法(,指定域,动态设置),注意不允许携带认证头和cookies
//预检查间隔时间 ‘Access-Control-Max-Age: 1800’ //允许的请求类型
‘Access-Control-Allow-Methods:GET,POST,PUT,POST’ //列出必须携带的字段
‘Access-Control-Allow-Headers:x-requested-with,content-type’