Ajax 跨域解决方案

作者: 卓三阳 | 来源:发表于2017-11-17 23:42 被阅读186次

在解决Ajax跨域问题之前,我们先一起来看看什么是浏览器的同源策略

一.浏览器同源政策

  • 含义
    1995年,同源政策由 Netscape 公司引入浏览器。目前,所有浏览器都实行这个政策。
    最初,它的含义是指,A网页设置的 Cookie,B网页不能打开,除非这两个网页"同源"。所谓"同源"指的是"三个相同"。

协议相同
域名相同
端口相同

举例来说,http://www.guangzhou.com/p/page.html这个网址,协议是http://,域名是 www.guangzhou.com,端口是80(默认端口可以省略)。它的同源情况如下。

http://www.guangzhou.com/dir/other.html: 同源
http://guangzhou.com/dir/other.html: 不同源(域名不同)
http://v2.www.guangzhou.com/dir/other.html:不同源(域名不同)
http://www.guangzhou.com:81/dir/other.html:不同源(端口不同)

  • 目的
    同源政策的目的,是为了保证用户信息的安全,防止恶意的网站窃取数据。
    设想这样一种情况:A网站是一家银行,用户登录以后,又去浏览其他网站。如果其他网站可以读取A网站的 Cookie,会发生什么?
    很显然,如果 Cookie 包含隐私(比如存款总额),这些信息就会泄漏。更可怕的是,Cookie 往往用来保存用户的登录状态,如果用户没有退出登录,其他网站就可以冒充用户,为所欲为。因为浏览器同时还规定,提交表单不受同源政策的限制。
    由此可见,"同源政策"是必需的,否则 Cookie 可以共享,互联网就毫无安全可言了。

  • 限制范围
    随着互联网的发展,"同源政策"越来越严格。目前,如果非同源,共有三种行为受到限制。

(1) Cookie、LocalStorage 和 IndexDB 无法读取。
(2) DOM 无法获得。
(3) AJAX 请求不能发送。

虽然这些限制是必要的,但是有时很不方便,合理的用途也受到影响。

在同源策略下,在某个服务器下的页面是无法获取到该服务器以外的数据的,但img、iframe、script等标签是个例外,这些标签可以通过src属性请求到其他服务器上的数据。

我们下面只专注于ajax跨域请求!!!


二.如何解决ajax跨域

一般ajax跨域就是通过代理,JSONP或者CORS三种方式解决(注意,现在JSONP很少用了,所以了解下即可)

(1)JSONP方式解决跨域问题

jsonp解决跨域问题是一个比较古老的方案(实际中不推荐使用),这里做简单介绍(实际项目中如果要使用JSONP,一般会使用JQ等对JSONP进行了封装的类库来进行ajax请求)
实现原理
JSONP之所以能够用来解决跨域方案,主要是因为 <script> 脚本拥有跨域能力,而JSONP正是利用这一点来实现。具体原理如图

jsonp-theory.png

实现流程
客户端网页网页通过添加一个<script>元素,向服务器请求JSON数据,这种做法不受同源政策限制
当我们通过JSONP模式请求跨域资源时,服务器返回给客户端一段javascript代码,这段javascript代码自动调用客户端回调函数。
客户端

jsonp.png

服务器端(PHP)

<?php
$staff = array
    (
        array("name" => "洪七", "number" => "101", "sex" => "男", "job" => "总经理"),
        array("name" => "郭靖", "number" => "102", "sex" => "男", "job" => "开发工程师"),
        array("name" => "黄蓉", "number" => "103", "sex" => "女", "job" => "产品经理")
    );

$jsonp = $_GET["callback"];
    //检查是否有员工编号的参数
if (!isset($_GET["number"]) || empty($_GET["number"])) {
        echo $jsonp . '({"success":false,"msg":"参数错误"})';
        return;
    }

//获取number参数
$number = $_GET["number"];
$result = $jsonp . '({"success":false,"msg":"没有找到员工。"})';
    
//遍历$staff多维数组,查找key值为number的员工是否存在,如果存在,则修改返回结果
foreach ($staff as $value) {
    if ($value["number"] == $number) {
        $result = $jsonp . '({"success":true,"msg":"找到员工:员工编号:' . $value["number"] .
                            ',员工姓名:' . $value["name"] . 
                            ',员工性别:' . $value["sex"] . 
                            ',员工职位:' . $value["job"] . '"})';
        break;
        }
    }
 echo $result;

由于<script>元素请求的脚本,直接作为代码运行。这时,只要浏览器定义了foo函数,该函数就会立即调用。作为参数的JSON数据被视为JavaScript对象,而不是字符串,因此避免了使用JSON.parse的步骤。
注意,一般的JSONP接口和普通接口返回数据是有区别的,所以接口如果要做JSONO兼容,需要进行判断是否有对应callback关键字参数,如果有则是JSONP请求,返回JSONP数据,否则返回普通数据

附(JQ对JSONP进行了封装的类库来进行ajax请求):


Jq-Jsonp.png

使用注意
基于JSONP的实现原理,所以JSONP只能是“GET”请求,不能进行较为复杂的POST和其它请求,所以遇到那种情况,就得参考下面的CORS解决跨域了(所以如今它也基本被淘汰了)

(2)CORS解决跨域问题

CORS请求原理
CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。

基本上目前所有的浏览器都实现了CORS标准(IE10以下不支持),其实目前几乎所有的浏览器ajax请求都是基于CORS机制的,只不过可能平时前端开发人员并不关心而已(所以说其实现在CORS解决方案主要是考虑后台该如何实现的问题)。

cors-theory.png

如何判断是否是简单请求?

浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。只要同时满足以下两大条件,就属于简单请求。

  • 请求方法是以下三种方法之一:HEAD,GET,POST

  • HTTP的头信息不超出以下几种字段:

Accept

Accept-Language

Content-Language

Last-Event-ID

Content-Type(只限于三个值application/x-www-form-urlencoded、 multipart/form-data、text/plain)

凡是不同时满足上面两个条件,就属于非简单请求。

实现——PHP后台配置
PHP后台的配置几乎是所有后台中最为简单的,遵循如下步骤即可:
第一步:配置Php 后台允许跨域

<?php
header('Access-Control-Allow-Origin:*');  //支持全域名访问,不安全,部署后需要固定限制为客户端网址
header('Access-Control-Allow-Methods:POST,GET,OPTIONS,DELETE'); //支持的http 动作
header('Access-Control-Allow-Headers:x-requested-with,content-type');  //响应头 请按照自己需求添加。

实现——Node.js后台配置(express框架)

app.all('*', function(req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "X-Requested-With");
    res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
    res.header("X-Powered-By", ' 3.2.1')
        //这段仅仅为了方便返回json而已
    res.header("Content-Type", "application/json;charset=utf-8");
    if(req.method == 'OPTIONS') {
        //让options请求快速返回
        res.sendStatus(200); 
    } else { 
        next(); 
    }
});
(3)代理请求方式解决跨域问题

这种方式是通过后台(ASP、PHP、JAVA、ASP.NET)获取其他域名下的内容,然后再把获得内容返回到前端,这样因为在同一个域名下,所以就不会出现跨域的问题。

实现过程
比如在广州的WEB服务器的后台(www.guangzhou.com/proxy-shanghaiservice.php)来调用上海(www.shanghai.com/service.php)的服务,然后把响应的结果返回前端,这样前端调用广州同域名的服务就和调用上海的服务效果相同了。


参考资料:
浏览器同源政策及其规避方法

相关文章

  • ajax跨域请求

    ajax跨域请求(jsonp) 利用JSONP解决AJAX跨域问题的原理与jQuery解决方案JSONP jQue...

  • 最全解决跨域问题方案,包括post跨域

    ajax跨域,这应该是最全的解决方案了

  • ajax跨域请求问题的五种解决方案

    ajax跨域请求问题的五种解决方案 方案一: 使用跨域资源共享代理(corsproxy) 方案二: 使用jsonp...

  • 解决ajax跨域问题

    Jsonp解决ajax跨域问题 CORS解决ajax跨域问题

  • PHP Ajax 跨域问题最佳解决方案

    PHP Ajax 跨域问题最佳解决方案 本文通过设置Access-Control-Allow-Origin来实现跨...

  • php ajax跨域访问

    PHP Ajax 跨域问题最佳解决方案 本文通过设置Access-Control-Allow-Origin来实现跨...

  • 前端跨域

    什么是ajax跨域 ajax跨域的原理 ajax出现请求跨域错误问题,主要原因就是因为浏览器的“同源策略”,可以参...

  • 跨域

    跨域:ajax 不能跨域img css script 标签 可以跨域例如:《img src="images/...

  • Http浅析【2】——ajax跨域问题

    视频参考:ajax跨域完全讲解 本文精华版:【综合】ajax跨域问题 什么是跨域问题 简单来讲,当前台调用后台,如...

  • 跨域解决方案

    跨域解决方案: 1.为什么会有跨域问题? 这是由于浏览器的同源策略,限制了不同源的资源进行交互(不允许用AJAX(...

网友评论

    本文标题:Ajax 跨域解决方案

    本文链接:https://www.haomeiwen.com/subject/bryjvxtx.html