Ajax跨域请求问题

Ajax跨域请求问题

什么是跨域?

跨域,指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器施加的安全限制。

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

2.同源策略目的
是为了保证用户信息的安全,防止恶意的网站窃取数据

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


3.同源策略限制范围
随着互联网的发展,"同源政策"越来越严格。目前,如果非同源,共有三种行为受到限制
    (1) Cookie、LocalStorage 和 IndexDB 无法读取
    (2) DOM 无法获得
    (3) AJAX 请求不能发送

所谓同源是指,域名,协议,端口均相同

http://www.123.com/index.html 调用 http://www.123.com/server.php (非跨域)

http://www.123.com/index.html 调用 http://www.456.com/server.php (主域名不同:123/456,跨域)

http://abc.123.com/index.html 调用 http://def.123.com/server.php (子域名不同:abc/def,跨域)

http://www.123.com:8080/index.html 调用 http://www.123.com:8081/server.php (端口不同:8080/8081,跨域)

http://www.123.com/index.html 调用 https://www.123.com/server.php (协议不同:http/https,跨域)

请注意:localhost和127.0.0.1虽然都指向本机,但也属于跨域。
原因:跨域是a页面想要获取b页面资源,如果a,b页面的协议、域名、端口号、子域名不同,所进行的访问都是跨域的,而浏览器一般为了安全都限制了跨域访问,也就是不允许跨域访问资源
浏览器处于同源策略的安全性考虑 会把服务器返回的数据进行劫持

!!!协议相同 域名相同 端口号相同 才不会受同源策略影响

跨域会阻止什么操作?

浏览器是从两个方面去做这个同源策略的,一是针对接口的请求,二是针对Dom的查询

1.阻止接口请求
2.阻止dom获取和操作

解决办法:JSONP CORS跨域

1、JSONP:

JSONP是服务器与客户端跨源通信的常用方法。最大特点就是简单适用,老式浏览器全部支持,服务器改造非常小
!!!需要目标服务器配合一个callback函数
  • JSONP是一个非官方协议,它允许在服务器端集成script tags返回至客户端,通过javascript callback的形式实现跨域访问。

  • 基本思想:网页通过添加一个<script>元素,向服务器请求JSON数据,这种做法不受同源策略限制;服务器收到请求后,将数据放在一个指定名字的回调函数里传回来

即利用某些HTML的标签不受同源策略的限制 比如:image script
缺点:只支持get请求 不支持post请求
原生实现
回调函数需要写到 script src=“http://test.com/data.php?callback=dosomething”></script前面
   // 处理服务器返回回调函数的数据
    <script type="text/javascript">
        function dosomething(res){
            // 处理获得的数据
            console.log(res.data)
        }
    </script>
   
   <script src="http://test.com/data.php?callback=dosomething"></script>
    // 向服务器test.com发出请求,该请求的查询字符串有一个callback参数,用来指定回调函数的名字
jQuery ajax
Jsonp会自动生成默认回调函数
    $.ajax({
        url: 'http://www.test.com:8080/login',
        type: 'get',
        dataType: 'jsonp',  // 请求方式为jsonp
        jsonpCallback: "handleCallback",    // 自定义回调函数名
        data: {}
    });
getJson()发送跨域请求
$.getJson("http://www.test.com:8080/login",
function(res){
alert(res.data);
});
Vue.js
    this.$http.jsonp('http://www.domain2.com:8080/login', {
        params: {},
        jsonp: 'handleCallback'
    }).then((res) => {
        console.log(res); 
    })

2、CORS跨域

CORS 是跨域资源分享(Cross-Origin Resource Sharing)的缩写。它是 W3C 标准,属于跨源 AJAX 请求的根本解决方法。

工作流程:在检测到你发送的Ajax的请求不是同源请求时 会在Http头部添加一个字段Origin

1、普通跨域请求:只需服务器端设置Access-Control-Allow-Origin

2、带cookie跨域请求:前后端都需要进行设置

**【前端设置】**根据xhr.withCredentials字段判断是否带有cookie

a、前端代码(需要判断浏览器是否支持情况)
function createCORSRequest(method, url) {
      var xhr = new XMLHttpRequest();
      if ("withCredentials" in xhr) {
     
        // 此时即支持CORS的情况
        // 检查XMLHttpRequest对象是否有“withCredentials”属性
        // “withCredentials”仅存在于XMLHTTPRequest2对象里
        xhr.open(method, url, true);
     
      } else if (typeof!= "undefined") {
     
        // 否则检查是否支持XDomainRequest,IE8和IE9支持
        // XDomainRequest仅存在于IE中,是IE用于支持CORS请求的方式
        xhr = new XDomainRequest();
        xhr.open(method, url);
     
      } else {
     
        // 否则,浏览器不支持CORS
        xhr = null;
     
      }
      return xhr;
    }
     
    var xhr = createCORSRequest('GET', url);
    if (!xhr) {
      throw new Error('CORS not supported');
    }


b、服务器端
response.addHeader(‘Access-Control-Allow-Origin:*’);//允许所有来源访问 
response.addHeader(‘Access-Control-Allow-Method:POST,GET’);//允许访问的方式
原生ajax
    var xhr = new XMLHttpRequest(); // IE8/9需用window.XDomainRequest兼容
     
    // 前端设置是否带cookie
    xhr.withCredentials = true;
     
    xhr.open('post', 'http://www.domain2.com:8080/login', true);
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    xhr.send('user=admin');
     
    xhr.onreadystatechange = function() {
        if (xhr.readyState == 4 && xhr.status == 200) {
            alert(xhr.responseText);
        }
    };
jQuery ajax
$.ajax({
   url: 'http://www.test.com:8080/login',
   type: 'get',
   data: {},
   xhrFields: {
       withCredentials: true    // 前端设置是否带cookie
   },
   crossDomain: true,   // 会让请求头中包含跨域的额外信息,但不会含cookie
});
 
vue-resource
Vue.http.options.credentials = true

【服务端设置】

服务器端对于CORS的支持,主要是通过设置Access-Control-Allow-Origin来进行的。如果浏览器检测到相应的设置,就可以允许Ajax进行跨域的访问。
Java后台
/*
 * 导入包:import javax.servlet.http.HttpServletResponse;
 * 接口参数中定义:HttpServletResponse response
 */
 
// 允许跨域访问的域名:若有端口需写全(协议+域名+端口),若没有端口末尾不用加'/'
response.setHeader("Access-Control-Allow-Origin", "http://www.domain1.com"); 
 
// 允许前端带认证cookie:启用此项后,上面的域名不能为'*',必须指定具体的域名,否则浏览器会提示
response.setHeader("Access-Control-Allow-Credentials", "true"); 
 
// 提示OPTIONS预检时,后端需要设置的两个常用自定义头
response.setHeader("Access-Control-Allow-Headers", "Content-Type,X-Requested-With");
Nodejs后台
    var http = require('http');
    var server = http.createServer();
    var qs = require('querystring');
     
    server.on('request', function(req, res) {
        var postData = '';
     
        // 数据块接收中
        req.addListener('data', function(chunk) {
            postData += chunk;
        });
     
        // 数据接收完毕
        req.addListener('end', function() {
            postData = qs.parse(postData);
     
            // 跨域后台设置
            res.writeHead(200, {
                'Access-Control-Allow-Credentials': 'true',     // 后端允许发送Cookie
                'Access-Control-Allow-Origin': 'http://www.domain1.com',    // 允许访问的域(协议+域名+端口)
                /* 
                 * 此处设置的cookie还是domain2的而非domain1,因为后端也不能跨域写cookie(nginx反向代理可以实现),
                 * 但只要domain2中写入一次cookie认证,后面的跨域接口都能从domain2中获取cookie,从而实现所有的接口都能跨域访问
                 */
                'Set-Cookie': 'l=a123456;Path=/;Domain=www.domain2.com;HttpOnly'  // HttpOnly的作用是让js无法读取cookie
            });
     
            res.write(JSON.stringify(postData));
            res.end();
        });
    });
     
    server.listen('8080');
    console.log('Server is running at port 8080...');
PHP后台
    <?php
     header("Access-Control-Allow-Origin:*");
Apache需要使用mod_headers模块来激活HTTP头的设置,它默认是激活的。你只需要在Apache配置文件的Directory, Location, Files或VirtualHost的配置里加入以下内容即可
Header set Access-Control-Allow-Origin 

代理

Node中间件代理(两次跨域)

实现原理:同源策略是浏览器需要遵循的标准,而如果是服务器向服务器请求就无需遵循同源策略。
代理服务器,需要做以下几个步骤:

  • 接受客户端请求 。
  • 将请求 转发给服务器。
  • 拿到服务器 响应 数据。
  • 将 响应 转发给客户端

附:https://www.cnblogs.com/fundebug/p/10329202.html
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值