Ajax跨域请求之同源政策、跨域请求 & 实现跨域请求之jsonp原理、jQuery实现跨域请求、CORS跨域 & XML格式-过时 & ajax请求遵循http协议

Ajax跨域请求之同源政策、跨域请求 & 实现跨域请求之jsonp原理、jQuery实现跨域请求、CORS跨域 & XML格式-过时 & ajax请求遵循http协议

3. Ajax跨域请求

3.1 同源政策

1995年,同源政策由 Netscape(网景) 公司引入浏览器。目前,所有浏览器都实行这个政策。

最初,它的含义是指,A 网站设置的 Cookie,B 网站不能打开,除非这两个网页同源。所谓同源指的是三个相同。

  • 协议相同(http https)
  • 域名相同
  • 端口相同(http默认80端口,https默认443端口)

在这里插入图片描述

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

  • Cookie无法读取。
  • DOM 无法获得。
  • AJAX 请求无效(可以发送,但浏览器会拒绝接受响应)。

3.2 什么是跨域请求

其实,了解了什么是同源政策,就知道什么是跨域请求了。

在发送Ajax请求的时候,请求的地址只要违反了同源政策,那么就属于跨域请求。

3.3 实现跨域请求的方案–JSONP

1)JSONP简介

JSON with Padding,是一种借助于 script 标签发送跨域请求的技巧。

其原理就是在客户端借助 script 标签请求服务端的一个地址,服务端的这个地址返回一段带有调用某个全局函数调用的 JavaScript 脚本(而非一段 HTML),将原本需要返回给客户端的数据通过参数传递给这个函数,函数中就可以得到原本服务端想要返回的数据。

以后绝大多数情况都是采用 JSONP 的手段完成不同源地址之间的跨域请求

2)使用JSONP实现跨域请求

  1. 首先得创建两个服务器,一个服务器(:3000)向另外一个服务器(:4000)发送请求

在这里插入图片描述
在这里插入图片描述

  1. 在3000里面写一个HTML页面index.html

    扫描二维码关注公众号,回复: 15063029 查看本文章
  2. 在3000里面,app.js中,返回index.html

    app.get('/index.html', (req, res) => {
          
          
        res.sendFile(__dirname + '/index.html');
    })
    

    重启服务器,此时,访问127.0.0.1:3000/index.html 就可以看到页面

  3. 在3000中的 index.html 中,通过script的src属性,请求4000网站中的一个接口

    <script src="http://127.0.0.1:4000/getHeroes"></script>
    
  4. 到4000中,写接口 getHeroes,完成响应

    app.get('/getHeroes', (req, res) => {
          
          
        // 返回的内容,只要符合JS的语法即可
        // res.send('hello');
        res.send('alert(123)');
    })
    

    写好之后,4000要重启服务器

  5. 刷新页面就可以看到弹出框了

    <script src="http://127.0.0.1:4000/getHeroes"></script>
    

3)实现跨域传输数据

前面实现了跨域请求。如果4000网站返回一个调用函数的字符串,那么3000网站接收到之后,也会执行一个函数。然后给函数传递一个参数,这个参数就是要传输的数据。

  1. 4000网站,返回一个调用函数的字符串

    app.get('/getHeroes', (req, res) => {
          
          
        // res.send('hello');
        // res.send('alert(1234);');
    
        let heroes = [
            {
          
          name: '曹操', age: 30},
            {
          
          name: '鲁达', age: 31}
        ];
        heroes = JSON.stringify(heroes);
    
        res.send('abc('+heroes+')');
    });
    
  2. 3000网站,要提前准备好一个叫做abc的函数,用于接收4000返回的数据

    <script>
        // 输出4000网站返回的内容
        // console.log(aa);
    
        // 为了配合4000网站的要求,所以要定义一个abc函数
        function abcd (res) {
            
            
            console.log(res);
        }
    </script>
    
    <script src="http://127.0.0.1:4000/getHeroes"></script>
    

    这样就可以实现跨域请求了。并且也实现了数据的传输。

    问题是两个网站的函数名字如何统一?大家有一个约定,请求的时候,要把你的函数名传递给4000网站,并且参数名必须是callback。

  3. 3000网站中,将函数名以参数的形式,传递过去

    <script>
        // 输出4000网站返回的内容
        // console.log(aa);
    
        // 为了配合4000网站的要求,所以要定义一个abc函数
        function abc(res) {
            
            
            console.log(res);
        }
    </script>
    
    <script src="http://127.0.0.1:4000/getHeroes?callback=abc"></script>
    
  4. 4000网站中,获取地址栏的callback参数,值就是函数的名字

    app.get('/getHeroes', (req, res) => {
          
          
        // res.send('hello');
        // res.send('alert(1234);');
    
        let heroes = [
            {
          
          name: '曹操', age: 30},
            {
          
          name: '鲁达', age: 31}
        ];
        heroes = JSON.stringify(heroes);
    
        // 获取函数名
        let fn = req.query.callback;
        // res.send('alert(' + heroes + ')');
        res.send(fn + '('+heroes+')');
    });
    

实例

1、新建客户端3000文件夹和服务器端4000文件夹,并初始化

npm init -y
npm i express

2、新建app.js

3000/app.js

const express = require('express');
const ap = express();
app.listen(3000, () => console.log('3000 start'));

4000/app.js

const express = require('express')
const app = express()
app.listen(4000, () => console.log('4000 start'))

3、启动项目

node .\app.js

nodemon .\app.js

效果

在这里插入图片描述

4、jsonp代码

在这里插入图片描述

代码

3000/index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <img src="https://gss3.bdstatic.com/84oSdTum2Q5BphGlnYG/timg?wapp&quality=80&size=b150_150&subsize=20480&cut_x=0&cut_w=0&cut_y=0&cut_h=0&sec=1369815402&srctrace&di=0767d0a97b3985dc375171590995e75e&wh_rate=null&src=http%3A%2F%2Fimgsrc.baidu.com%2Fforum%2Fpic%2Fitem%2F562c11dfa9ec8a13467195f0f903918fa0ecc0b3.jpg"
    />
    <script src="https://libs.baidu.com/jquery/2.1.4/jquery.min.js"></script>
    <!-- JSONP原理代码 -->
    <script>
        // 4000网站返回的内容,被3000网站当做js代码执行了
        function abcd (res) {
      
      
            console.log(res);
        }
    </script>
    <script src="http://127.0.0.1:4000/getHeroes?callback=abcd"></script> 

</body>

</html>

4000/app.js

const express = require('express')
const app = express()
app.listen(4000, () => console.log('4000 start'))

// 定义一个接口
app.get('/getHeroes', (req, res) => {
    
    
  // res.send('hello');
  // res.send('alert(1234);');

  let heroes = [
    {
    
     name: '曹操', age: 30 },
    {
    
     name: '鲁达', age: 31 },
  ]
  heroes = JSON.stringify(heroes)

  // 获取函数名
  let fn = req.query.callback
  // res.send('alert(' + heroes + ')');
  res.send(fn + '(' + heroes + ')')
})

4)jQuery封装的ajax方法跨域请求

  1. 在3000网站中,jsonp2.html 中引入一个jQuery文件,为了方便(引入自己的jQuery,自己就得写处理静态资源文件的代码),引入的是百度提供的jquery

  2. 使用jQuery提供的ajax方法,实现跨域访问

    3000/index.html

    <!-- 使用jQuery提供的ajax方法,实现跨域请求 -->
    <!-- 下面引入百度提供的jQuery,需要联网 -->
    <script src="http://libs.baidu.com/jquery/2.1.4/jquery.min.js"></script>
    
    <script>
        $.ajax({
            
            
            type: 'GET',
            url: 'http://127.0.0.1:4000/getHeroes',
            dataType: 'jsonp',  / 这里一定要使用jsonp
            success: function (res) {
            
            
                console.log(res)
            }
        });
    </script>
    

    4000/app.js文件不变,同上

    3000/index.html完整代码

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
    </head>
    
    <body>
        <img src="https://gss3.bdstatic.com/84oSdTum2Q5BphGlnYG/timg?wapp&quality=80&size=b150_150&subsize=20480&cut_x=0&cut_w=0&cut_y=0&cut_h=0&sec=1369815402&srctrace&di=0767d0a97b3985dc375171590995e75e&wh_rate=null&src=http%3A%2F%2Fimgsrc.baidu.com%2Fforum%2Fpic%2Fitem%2F562c11dfa9ec8a13467195f0f903918fa0ecc0b3.jpg"
        />
        <script src="https://libs.baidu.com/jquery/2.1.4/jquery.min.js"></script>
        <script>
            $.ajax({
            
            
                type: 'GET',
                url: 'http://127.0.0.1:4000/getHeroes',
                dataType: 'jsonp',
                success: function(res) {
            
            
                    console.log(res)
                }
            });
        </script>
    
        <!-- JSONP原理代码 -->
        <!-- <script>
            // 4000网站返回的内容,被3000网站当做js代码执行了
            function abcd (res) {
                console.log(res);
            }
        </script>
        <script src="http://127.0.0.1:4000/getHeroes?callback=abcd"></script> -->
    
    </body>
    
    </html>
    

    打开页面效果

在这里插入图片描述

3.4 实现跨域请求的方案–CORS

通过在**请求的路由中**设置header头,可以实现跨域。不过这种方式只有最新的浏览器(IE10)才支持。

Cross Origin Resource Share,跨域资源共享

app.get('/time', (req, res) => {
    
    
  // // 允许任意源访问,不安全
  // res.setHeader('Access-Control-Allow-Origin', '*')
  // 允许指定源访问
  res.setHeader('Access-Control-Allow-Origin', 'http://www.xxx.com')
  res.send(Date.now().toString())
})

这种方案无需客户端作出任何变化(客户端不用改代码),只是在被请求的服务端响应的时候添加一个 Access-Control-Allow-Origin 的响应头,表示这个资源是否允许指定域请求。

实例

cors效果

在这里插入图片描述

代码-cors代码

在这里插入图片描述

代码

3000客户端系列代码

3000/app.js

const express = require('express');
const app = express();
app.listen(3000, () => console.log('3000 start'));

// 显示index.html
app.get('/index.html', (req, res) => {
    
    
    res.sendFile(__dirname + '/index.html');
});

app.get('/cors.html', (req, res) => {
    
    
    res.sendFile(__dirname + '/cors.html');
});

3000/index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <img src="https://gss3.bdstatic.com/84oSdTum2Q5BphGlnYG/timg?wapp&quality=80&size=b150_150&subsize=20480&cut_x=0&cut_w=0&cut_y=0&cut_h=0&sec=1369815402&srctrace&di=0767d0a97b3985dc375171590995e75e&wh_rate=null&src=http%3A%2F%2Fimgsrc.baidu.com%2Fforum%2Fpic%2Fitem%2F562c11dfa9ec8a13467195f0f903918fa0ecc0b3.jpg"
    />
    <script src="https://libs.baidu.com/jquery/2.1.4/jquery.min.js"></script>
    <script>
        $.ajax({
      
      
            type: 'GET',
            url: 'http://127.0.0.1:4000/getHeroes',
            dataType: 'jsonp',
            success: function(res) {
      
      
                console.log(res)
            }
        });
    </script>

    <!-- JSONP原理代码 -->
    <!-- <script>
        // 4000网站返回的内容,被3000网站当做js代码执行了
        function abcd (res) {
            console.log(res);
        }
    </script>
    <script src="http://127.0.0.1:4000/getHeroes?callback=abcd"></script> -->

</body>

</html>

3000/cors.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <script>
        var xhr = new XMLHttpRequest();
        xhr.open('GET', 'http://127.0.0.1:4000/aa');
        xhr.send();
        xhr.onload = function () {
      
      
            console.log(this.response)
        }
    </script>
</body>
</html>
4000服务端系列代码

4000/app.js

const express = require('express')
const app = express()
app.listen(4000, () => console.log('4000 start'))

// 定义一个接口
app.get('/getHeroes', (req, res) => {
    
    
  // res.send('hello');
  // res.send('alert(1234);');

  let heroes = [
    {
    
     name: '曹操', age: 30 },
    {
    
     name: '鲁达', age: 31 },
  ]
  heroes = JSON.stringify(heroes)

  // 获取函数名
  let fn = req.query.callback
  // res.send('alert(' + heroes + ')');
  res.send(fn + '(' + heroes + ')')
})

// 实现CORS跨域的接口
app.get('/aa', (req, res) => {
    
    
  // 加入CORS头
  // res.setHeader('Access-Control-Allow-Origin', '*');
  res.setHeader('Access-Control-Allow-Origin', 'http://127.0.0.1:3000')
  res.end('hello')
})

4.XML

HTML:超文本标记语言

XML: eXtension Markup Language 可扩展标记语言

一种数据描述手段

老掉牙的东西,简单演示一下,不在这里浪费时间,基本现在的项目不用了。

淘汰的原因:数据冗余太多

<?xml version="1.0" encoding="UTF-8" ?>
<students>
	<stu id="1">
    	<name>张三</name>
        <age>18</age>
        <sex></sex>
        <other height="175cm" weight="65kg" />
    </stu>
    <stu id="2">
    	<name>李四</name>
        <age>20</age>
        <sex></sex>
        <other height="170cm" weight="60kg" />
    </stu>
</students>

XML语法规范:

  • 和html写法差不多
  • 有且只有一个根标签
  • 标签区分大小写
  • 标签必须闭合
  • 属性值必须加引号

如果服务器返回的是XML格式的数据,JS收到数据之后,把收到的数据当做document对象来处理即可

5.原生的xhr获取请求报文和响应报文的信息

ajax请求,也是遵循http协议的。

ajax请求过程中,可以设置请求报文、也可以获取响应报文

<script>
    // 请求报文:
    // 行
    // 头
    // 体
    // 响应报文:
    // 行
    // 头
    // 体
    var xhr = new XMLHttpRequest();
    xhr.open('post', '/abc'); // 体现了请求行的内容(请求方式和接口地址)
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); // 体现了请求头
    xhr.send('aa=xxx&bb=yyy'); // 体现了请求体
    xhr.onload = function () {
      
      
        console.log(this.status); // 体现了响应行的状态码
        console.log(this.statusText); // 体现了响应行的状态描述信息
        console.log(this.getAllResponseHeaders()); // 体现了所有的响应头
        console.log(this.getResponseHeader('content-length')); // 体现了所有的响应头
        console.log(this.response); // 体现了响应体的内容
    }
</script>

实例

1、新建http文件夹,并初始化

npm init -y
npm i express

2、搭建服务器

http/app.js

const express = require('express');
const app = express();

app.listen(3000, () => console.log('kaiqi'));

app.get('/index.html', (req, res) => {
    
    
    res.sendFile(__dirname + '/index.html');
});

app.post('/abc', (req, res) => {
    
    
    res.send('hello');
});

3、访问页面

http/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <script>
        // 请求报文:
            // 行
            // 头
            // 体
        // 响应报文:
            // 行
            // 头
            // 体
        var xhr = new XMLHttpRequest();
        xhr.open('post', '/abc'); // 体现了请求行的内容(请求方式和接口地址)
        xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); // 体现了请求头
        xhr.send('aa=xxx&bb=yyy'); // 体现了请求体
        xhr.onload = function () {
      
      
            console.log(this.status); // 体现了响应行的状态码
            console.log(this.statusText); // 体现了响应行的状态描述信息
            console.log(this.getAllResponseHeaders()); // 体现了所有的响应头
            console.log(this.getResponseHeader('content-length')); // 体现了所有的响应头
            console.log(this.response); // 体现了响应体的内容
        }
    </script>
</body>
</html>

4、http终端中,启动服务

node ./app.js

5、页面访问,显示数据

地址——http://127.0.0.1:3000/index.html

6、效果

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_44867717/article/details/130234450