ajax学习笔记-同源政策

同源政策

如果两个页面拥有相同的协议、域名和端口,那么这两个页面就属于同一个源,其中只要有一个不相同,就是不同源。

示例如下:
http://www.example.com/dir/page.html
http://www.example.com/dir2/other.html:同源
http://example.com/dir/other.html:不同源(域名不同)
http://www.example.com:81/dir/other.html:不同源(端口不同)
https://www.example.com/dir/page.html:不同源(协议不同)

同源政策是为了保证用户信息的安全,防止恶意的网站窃取数据。最初的同源政策是指 A 网站在客户端设置的 Cookie,B网站是不能访问的。

随着互联网的发展,同源政策也越来越严格,在不同源的情况下,其中有一项规定就是无法向非同源地址发送Ajax 请求,如果请求,浏览器就会报错(拒绝接收服务器端的返回结果)。

解决方案

一.JSONP解决同源限制问题

jsonp 是 json with padding 的缩写,它不属于 Ajax 请求,但它可以模拟 Ajax 请求。
实际上是绕过浏览器同源政策的限制,向非同源服务器端发送请求。

实际编写代码:

1.客户端:将非同源的服务器端请求地址写在 script 标签的 src 属性中。(script标签中的src属性拥有发送请求的能力,且不受同源政策的影响。但请求地址不管是什么样子的,都必须返回合法的js代码。)

    <script src="http://localhost:8889/test"></script>

2.客户端:在客户端全局作用域下定义函数 fn,且必须写在script 标签上面

    <script>
        function fn(data) {
            console.log('客户端的fn函数被调用了');
            console.log(data);
        }
    </script>

3.服务器端:调用函数fn,但是要写成字符串的形式,然后写在res.send()中。

//非同源服务器的app.js
app.get('/test', (req, res) => {
    // 返回函数调用的代码,但是函数调用是在客户端进行的
    const result = 'fn({name:"张三"})';
    res.send(result);
});
优化代码

1.将 script 请求的发送变成动态请求,动态创建script标签

    <script>
        //获取按钮
        var btn = document.getElementById('btn');
        //为按钮添加点击事件
        btn.onclick = function() {
            //创建script标签
            var script = document.createElement('script');
            //设置src属性
            script.src = 'http://localhost:8889/test';
            //将script标签追加到页面中
            document.body.appendChild(script);
            //监听script加载
            script.onload = function() {
                //将body中的script标签删除
                document.body.removeChild(script);
            }
        }
    </script>

2.客户端需要将函数名称传递到服务器端。

//修改客户端代码
//设置src属性
script.src = 'http://localhost:8889/test1?callback=fn';
//修改非同源服务器端代码app.js
app.get('/test1', (req, res) => {
    //接收客户端传递过来的函数名称
    const fnName = req.query.callback;
    //将函数名称对应的函数调用代码返回给客户端
    const result = fnName + '({name:"张三"})';
    res.send(result);
});

3.封装 jsonp 函数,方便请求发送。

//封装jsonp
function jsonp(options) {
            //创建script标签
            var script = document.createElement('script');
            //拼接字符串
            var params = '';
            for (var attr in options.data) {
                params += '&' + attr + '=' + options.data[attr];
            }
            // 生成随机函数名
            var fnName = 'myJsonp' + Math.random().toString().replace('.', '');
            //success已经不是全局函数了,服务器端返回函数调用找不到函数,想办法变成全局函数
            window[fnName] = options.success;      
            //设置src属性
            script.src = options.url + '?callback=' + fnName + params;
            //将script标签追加到页面中
            document.body.appendChild(script);
            //监听script加载
            script.onload = function() {
                //将body中的script标签删除
                document.body.removeChild(script);
            }
        }

//调用jsonp
 jsonp({
     //请求地址
     url: 'http://localhost:8889/test1',
     data: {
         name: 'lisi',
         age: 30
     },
     success: function(data) {
         console.log(123);
         console.log(data);
     }
 });

4.服务器端代码优化,jsonp方法直接将json对象转换为字符串并传递给客户端。

app.get('/test1', (req, res) => {
    // //接收客户端传递过来的函数名称
    // const fnName = req.query.callback;
    // //将函数名称对应的函数调用代码返回给客户端
    // //如果数据从数据库中获取,它是一个json对象
    // const data = { name: "张三" }
    // const result = fnName + '(' + data + ')';
    // res.send(result);

    //可以替换掉上面繁琐的代码
    res.jsonp({ name: 'lisi', age: 20 });
});

二.CORS跨域资源共享

CORS全称为 Cross-origin resource sharing,即跨域资源共享(跨域即非同源),它允许浏览器向跨域服务器发送 Ajax 请求,克服了 Ajax 只能同源使用的限制。简单来说,就是在服务器允许的情况下,就可以实现跨域访问。
该解决方案主要是在服务器端做一些配置,客户端保持原有的ajax代码不变。

跨域实现过程:
在这里插入图片描述
客户端向服务器端发送请求时,如果浏览器检测到这个请求是跨域的,就会自动在请求头中加入origin字段,字段值即当前发送请求的域信息(这个域信息即当前网站的页面地址,包括协议,域名,端口号)。服务器端根据字段值决定是否同意这次请求。但无论服务器端是否同意这次请求,都会给客户端一个正常的http响应。如果同意这次请求,服务器端会在响应头中加入Access-Control-Access-Origin字段(该字段值通常是访问服务器端的源信息或表示允许所有客户端访问的‘ * ’)。浏览器端会自动根据是否有这个响应头字段判断这次请求是否被同意。

代码实现:

//非同源服务器端app.js
//CROS跨域资源共享
app.use((req, res, next) => {
    //实际上都是设置在响应头中
    //1.允许哪些客户端访问该服务器
    res.header('Access-Control-Allow-Origin', '*');
    //2.允许客户端使用哪些请求方法访问该服务器
    res.header('Access-Control-Allow-Methods', 'get,post');
    next();
})

三.服务器端解决方案

同源政策是浏览器给予Ajax技术的限制,服务器端是不存在同源政策限制。
在这里插入图片描述
代码实现:

//A浏览器端
//获取按钮
var btn = document.getElementById('btn');
//为按钮添加点击事件
btn.onclick = function() {
   ajax({
       type: 'get',
       url: 'http://localhost:8888/server', //向自己获取数据
       success: function(data) {
           console.log(data);
       }
   });
};
//A服务器端
//向其他服务器端请求数据的模块
const request = require('request'); 

app.get('/server', (req, res) => {
    request('http://localhost:8889/cross', (err, response, body) => {
        //body就是请求的数据
        res.send(body);
    })
});
//B服务器端
app.get('/cross', (req, res) => {
    res.send('ok');
});

设置发送跨域请求时携带Cookie信息

在使用Ajax技术发送跨域请求时,默认情况下不会在请求中携带cookie信息。
如何设置?
客户端中,设置ajax对象:xhr.withCredentials = true;
服务器端中,设置响应头:res.header('Access-Control-Allow-Credentials', true);
注意:必须两者同时设置才能实现发送跨域请求时携带Cookie信息

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值