前后端分离

前后端分离的好处

  1. 最大的好处就是前端JS可以做很大部分的数据处理工作,对服务器的压力减小到最小。
  2. 后台错误不会直接反映到前台,错误接秒较为友好。
  3. 由于后台是很难去探知前台页面的分布情况,而这又是JS的强项,而JS又是无法独立和服务器进行通讯的。所以单单用后台去控制整体页面,又或者只靠JS完成效果,都会难度加大,前后台各尽其职可以最大程度的减少开发难度。

个人理解上存在两种解释

  1. 第一种只是单纯的前后端分离,实在物理层面上的,将View层的任务分配给前端,Controller和Model层给后端,这就存在一个问题,就是后端的同事需要去关注前端的展示逻辑、而前端只要存在变化,后端的数据处理需要做相应的改变。
  2. 第二种是基于职责层面上的分离,将View和Controller层分配的前端,后端只处理Model和业务处理,这就需要Controller使用Node.js,M-V-C对应的是JAVA/PHP-JAVASCRIPT、HTML、CSS-Node.js。

跨域问题存在的原因

随着前后端分离技术的越来越盛行,跨域问题也逐渐凸显了出来。跨域问题的根本原因:因为浏览器收到同源策略的限制,当前域名的js只能读取同域下的窗口属性。什么叫做同源策略?就是不同的域名, 不同端口, 不同的协议不允许共享资源的,保障浏览器安全。同源策略是针对浏览器设置的门槛。如果绕过浏览就能实现跨域,所以说早期的跨域都是打着安全路数的擦边球,都可以认为是 hack 处理。这一段是我从别的地方cp过来的,大家将就着看吧。

这里要注意的是,只有访问类型为xhr(XMLHttpRequest)的才会出现跨域。

跨域问题的解决方案

  • 修改浏览器的设置
  • 修改请求的方式:jsonp
  • CORS

修改浏览器配置解决跨域

以Google Chrome为例,浏览器以

"C:\ProgramFiles(x86)\Google\Chrome\Application\chrome.exe"--disable-web-security--user-data-dir

中模式打开,右键点击浏览器快捷方式,在目标中输入上述代码即可解决(不推荐)。

使用jsonp解决跨域

JQuery中的正常AJAX请求代码片段

$("#demo1").click(function(){$.ajax({url : 'http://www.tpadmin.top/Index/Test/crossDomain',data : {},type : 'get',success : function (res) {//No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1' is therefore not allowed access. 在执行时候报出的错误,这代表了跨域错误alert(res);}});
});

JQuery中的使用JSONP的AJAX请求代码:

$("#demo2").click(function(){$.ajax({url : 'http://www.tpadmin.top/Index/Test/crossDomain',data : {},type : 'get',dataType : 'jsonp', success : function (res) {alert(res);}});
});

这时候我们看到 请求的网址自动变成了

http://www.tpadmin.top/Index/Test/crossDomain?callback=jQuery331015214102388989237_1534993962395&_=1534993962396

这是为什么呢?原来由于跨域访问的只限制xhr类型的请求(上文中已经说了),所以js中就利用了这一特点,让服务端不在返回的是一个JSON格式的数据,而是返回一段JS代码,将JSON的数据以参数的形式传递到这个函数中,而函数的名称就是callback参数的值,所以我们还需要修改服务端的代码,代码如下:

<?php$callback = isset($_GET['callback'])?$_GET['callback']:'';if (!empty($callback)) {$arr = ['code' => 200, 'name' => 'cui'];$data = json_encode($arr);exit($callback . '(' . $data . ')');}
?>

OK,现在问题解决了,但是JSONP存在着诸多限制,下面将列出两个个我知道的:

  • JSONP只支持GET请求,什么?你要提交表单,sorry,此路不通
  • 它只支持跨域HTTP请求

虽然只有两个,但是让很多人不得不放弃它,所以出现了下面的解决办法。

CORS解决跨域

回归问题本质,跨域问题为什么会产生,上面已经说了,是由于浏览器的限制,那么在执行过程中有什么不同,下面两张度分析一下(主要看请求头的部分):

这是非跨域请求

这是跨域请求

这时我们发现跨域访问的请求头中存在Origin的字段,用来记录当前的访问域名,我们可以再服务端增加一个响应头Access-Control-Allow-Origin来告诉浏览器我们支持它获取就可以了,代码实现:

<?php
header('Access-Control-Allow-Origin:http://127.0.0.1');
$arr = ['code' => 200, 'name' => 'cui'];
echo $data = json_encode($arr);
?>

那如果我有多个域名进行跨域访问呢

<?php
$requestHeader = getallheaders();
$origin = isset($requestHeader['Origin'])?$requestHeader['Origin']:'';
switch ($origin) {case 'http://127.0.0.1':header('Access-Control-Allow-Origin:http://127.0.0.1');break;case 'http://localhost':header('Access-Control-Allow-Origin:http://localhost');break;default:break;
}
$arr = ['code' => 200, 'name' => 'cui'];
echo $data = json_encode($arr);
//注意,不支持下面这种写法
//header('Access-Control-Allow-Origin:http://localhost,http://127.0.0.1');
?>

或者直接写成(很不安全,不推荐这么写)

<?php
header('Access-Control-Allow-Origin:*');
$arr = ['code' => 200, 'name' => 'cui'];
echo $data = json_encode($arr);
?>

到这里,其实已经结束了,但还有一些其他的特殊情况

  1. 请求方法不是GET、HEAD、POST
  2. 请求头中存在自定义头
  3. Content-Type不是text/plain、multipart/form-data、application/x-www-form-urlencoded
  4. 希望获取到服务端的Cookie

为了应对种种限制,我们再来看一段代码

$("#demo1").click(function(){$.ajax({url : 'http://cui.tpadmin.top/crossDomain.php',data : {},type : 'PUT',contentType : 'application/json',header: {token:'asdfgqwerttyyazxcvbvb'},success : function (res) {alert(res);}});
});

虽然我们在服务端加入了Access-Control-Allow-Origin响应头,但是如果出现上面所说的情况时,我们需要做一些特殊的设置,修改服务端代码为:

<?php
//这里增加了两行代码
header('Access-Control-Allow-Headers:Content-Type');
header('Access-Control-Allow-Methods:PUT');
$requestHeader = getallheaders();
$origin = isset($requestHeader['Origin'])?$requestHeader['Origin']:'';
switch ($origin) {case 'http://127.0.0.1':header('Access-Control-Allow-Origin:http://127.0.0.1');break;case 'http://localhost':header('Access-Control-Allow-Origin:http://localhost');break;default:break;
}
$arr = ['code' => 200, 'name' => 'cui'];
echo $data = json_encode($arr);
?>

这里虽然成功了,但是我们发现每次请求的时候会出现两条请求记录(这个可不是我请求了两次,看下面截图)

这里我们需要进行一下区分(简单请求模式与非简单请求模式)

  1. 请求方法只能为GET、HEAD、POST
  2. 请求头中无自定义头
  3. Content-Type必须为text/plain、multipart/form-data、application/x-www-form-urlencoded

符合以上条件的为简单请求,否则为非简单请求,注意,非简单请求中,浏览器会默认发送两条请求,第一条为预检请求(OPTION),第二条为AJAX的请求,处于服务器的性能考量,我们需要将预检命令进行缓存,而不是每次都执行预检请求,我们可以修改代码如下:

<?php
header('Access-Control-Allow-Headers:Content-Type');
header('Access-Control-Allow-Methods:PUT');
//看这里
header('Access-Control-Max-Age:3600');
$requestHeader = getallheaders();
$origin = isset($requestHeader['Origin'])?$requestHeader['Origin']:'';
switch ($origin) {case 'http://127.0.0.1':header('Access-Control-Allow-Origin:http://127.0.0.1');break;case 'http://localhost':header('Access-Control-Allow-Origin:http://localhost');break;default:break;
}
$arr = ['code' => 200, 'name' => 'cui'];
echo $data = json_encode($arr);
?>

这次我请求了两次,发现第二次请求没有发送预检请求,新增加的代码代表允许缓存的时间(3600S)。

另外还有一些常用的方法,我都放到这里了,有需要的小伙伴可以参考

<?php
//支持Cookie
header('Access-Control-Allow-Credentials:true');
//支持自定义头
header('Access-Control-Allow-Headers:token,Content-Type,...');​

由于篇幅有限,Cookie的例子小伙伴们自己做就可以了,使用Cookie的时候需要注意Access-Control-Allow-Origin不可设置为*。

服务软件实现跨域

上面的例子实现了跨域访问,但是如果我不想在代码中修改,还有其他的方法吗,当然有了,我们可以直接修改服务软件,下面将从最常用的Apache与Nignx两个方面说明

基于Apache的服务

<VirtualHost *:80>ServerName localhostServerAlias localhostDocumentRoot "${INSTALL_DIR}/www"Header always set Access-Control-Allow-Header "PUT"Header always set Access-Control-Allow-Credentials "true"Header always set Access-Control-Max-Age "3600"#这里设置的为全匹配Header always set Access-Control-Allow-Origin "expr=%{req:origin}"#这里设置的为全匹配Header always set Access-Control-Allow-Headers "expr=%{req:Access-Control-Allow-Headers}"<Directory "${INSTALL_DIR}/www/">Options +Indexes +Includes +FollowSymLinks +MultiViewsAllowOverride AllRequire local</Directory>
</VirtualHost> 

这里说明一下,由于Apache都是模块管理,所以这里要想使用Header的话,需要加载mod_headers.so这个模块,去看一下自己的主配置文件,这个模块是否开启,如果没有开启,apache会启动失败的。

LoadModule headers_module modules/mod_headers.so

由于本人学艺不精,Apache的配置中的判断没有完全闹懂,所以这里没有进行区分的匹配,如果有大神知道,请指导一下,不胜感激。

基于Nignx的服务

在nignx服务的配置中修改为如下代码(注意位置,这个例子是修改本地的nignx,没有域名,如果没有熟悉过nignx的小伙伴可以自行百度)。

server {listen       80 default_server;listen       [::]:80 default_server;server_name  _;root         /usr/share/nginx/html;# Load configuration files for the default server block.include /etc/nginx/default.d/*.conf;location / {#支持其他请求add_header Access-Control-Allow-Methods PUT;#设置预检请求的缓存add_header Access-Control-Max-Age 3600;#允许Cookieadd_header Access-Control-Allow-Credentials true;#这里最好做判断,怕麻烦的话就写*,但是不建议if ($http_origin = http://localhost){add_header Access-Control-Allow-Origin http://localhost;}if ($http_origin = http://127.0.0.1){add_header Access-Control-Allow-Origin http://127.0.0.1;}#为了方便,这样写了add_header Access-Control-Allow-Headers $http_access_control_request_headers;if ($request_method = OPTIONS){return 200;}}error_page 404 /404.html;location = /40x.html {}error_page 500 502 503 504 /50x.html;location = /50x.html {}
}

另外再说一句,如果您使用的是JAVA的话,可以尝试一下正反向代理。

最后说明一下,本篇文章完全根据自己的学习以及经验所写,在严谨性上肯定有不足的地方,希望能帮到小伙伴们,如果发现问题,请及时联系我,谢谢。

前后端分离与跨域的解决方案(CORS的原理)相关推荐

  1. cors 前后端分离跨域问题_SpringBoot 实现前后端分离的跨域访问(CORS)

    序言:跨域资源共享向来都是热门的需求,使用CORS可以帮助我们快速实现跨域访问,只需在服务端进行授权即可,无需在前端添加额外设置,比传统的JSONP跨域更安全和便捷. 一.基本介绍 简单来说,CORS ...

  2. 解决java前后端分离端口跨域问题

    解决java前后端分离端口跨域问题 参考文章: (1)解决java前后端分离端口跨域问题 (2)https://www.cnblogs.com/mollie-x/p/10449686.html 备忘一 ...

  3. Vue flask前后端分离解决跨域

    Vue flask前后端分离解决跨域 安装axios 在项目目录下输入:npm install axios--save-dev 配置axios 在main.js中引入axios import axio ...

  4. Vue+Flask前后端分离 Vue3跨域配置

    Vue+Flask前后端分离 Vue3跨域配置 前端端口号为8080 后端端口号为5000 问题描述 问题解决 接口路径映射 前端端口号为8080 后端端口号为5000 后端端口API 代码片. @a ...

  5. 前后端分离的跨域解决方案

    声明: 在以往的开发中,前后端分离也不是像现在这么热门,所谓的前端工程师也只不过是写好静态页面由Java工程师或者php工程师嵌入到页面中进行开发,这或许加重了这些工程师的工作量,而且在样式调试上由纯 ...

  6. 前后端分离项目跨域问题及解决方案

    目录 1.什么是跨域 2.前后端分离项目中的跨域问题 3.方法一:SpringBoot后端进行处理 4.方法二:在Vue前端进行处理 5.总结 1.什么是跨域 请求同域资源: 在域名 (或 ip 地址 ...

  7. Spring Boot2.x-13前后端分离的跨域问题解决方法之Nginx

    文章目录 概述 浏览器同源策略 后台搭建 pom.xml interceptor 配置 Controller 启动测试 浏览器和session 后端工程发布到服务器上 问题复现 通过Nginx反向代理 ...

  8. 06-若依前后端分离项目跨域问题解决方式

    什么是跨域 跨域就是前后端分离项目前端无法把session等信息传递给后端服务器.跨域源自浏览器同源策略.同源策略是一种约定,同源策略会阻止一个域的javascript脚本和另外一个域的内容进行交互. ...

  9. 跨域详解!前后端分离解决跨域问题

    文章目录 一.为什么会出现跨域问题 二.什么是跨域 三.非同源限制 四.跨域问题的解决方式 Jsonp前后端配合 前端修改 后端修改 CORS 详解响应头 5. SpringBoot解决 [方式一]全 ...

最新文章

  1. 快捷键 = 效率,但 IDEA 快捷键记不住怎么办?
  2. python【数据结构与算法】内置函数enumerate(枚举) 函数(看不懂你来打我)
  3. linux 中shift的用法介绍
  4. CentOS7 systemctl tomcat常用配置
  5. PCA与LDA算法的解释,浅显易懂
  6. java swing 总结_java实验之swing图形用户界面程序设计及总结
  7. 红旗桌面版本最新运用方式和题目问题解答100例-4
  8. Java 网络教程: ServerSocket
  9. layer根据内容动态改变窗口高度
  10. angularJS使用rootscope创建父域和子模态框通用的属性与函数
  11. 谷歌 analytics.js 简要分析
  12. Linux-chmod
  13. Spring Boot-1 (IntelliJ IDEA + gradle)
  14. android 涟漪背景,Android 水波效果 | 涟漪效果 实现
  15. 解决烘焙光照贴图有黑斑
  16. gis计算频数_频数 (分析)
  17. 2023年最全盘点 | 16款跨平台应用程序开发框架
  18. C++ Pointer指针
  19. Oracle索引梳理系列(八)- 索引扫描类型及分析(高效索引必备知识)
  20. 新中新二代身份证读卡器DKQ-A16D C# Demo 无法运行问题

热门文章

  1. 我刚创建了一个开源项目OXmlEd,欢迎大家拍砖
  2. 云计算“生态”升维,百度智能云引领AI工业化承载制造业智能升级重任
  3. Abaqus启动失败 FlexNet Licensing error:-7,96
  4. 本周AI热点回顾:Github私有库无限协作、飞腾适配百度昆仑AI处理器、OpenAI发布神经网络可视化库
  5. AIStationV3.0 + GeForce RTX 3090 + 5280M5安装测试及故障处理
  6. 15、Python的元组类型
  7. 『CV学习笔记』图像处理透视变换(Python+Opencv)
  8. 学习《码农翻身》之精进
  9. 什么是DNS?DNS端口号是多少?什么是DNS服务,DNS服务器?DNS域名解析原理
  10. Spark编程基础-(二)Scala语言基础