06跨域

第一章: 跨域

1、 同源策略

同源策略(Same-Origin Policy)最早由 Netscape 公司提出,是浏览器的一种安全策略。

同源(同一个来源):协议、域名、端口号 必须完全相同 ==> 比如http://127.0.0.1:3000,后面的/server、/data等可以不同

违背同源策略就是跨域 ==> 比如http协议向https协议发送请求,a.com 向 b.com 发送请求,300端口向8000端口发送请求

AJAX默认遵循的是同源策略

<body>
    <h1>尚硅谷</h1>
    <button>点击获取用户数据</button>
    <script>
        const btn = document.querySelector('button');

        btn.onclick = function(){
            const x = new XMLHttpRequest();
            //这里因为是满足同源策略的, 所以 url 可以简写
            x.open("GET",'/data');
            //发送
            x.send();
            //
            x.onreadystatechange = function(){
                if(x.readyState === 4){
                    if(x.status >= 200 && x.status < 300){
                        console.log(x.response);
                    }
                }
            }
        }
    </script>
</body>
const express = require('express');

const app = express();

app.get('/home', (request, response)=>{
    //响应一个页面
    // dirname 前面是两个下划线
    response.sendFile(__dirname + '/index.html');
});

app.get('/data', (request, response)=>{
    response.send('用户数据');
});

app.listen(9000, ()=>{
    console.log("服务已经启动...");
});

2、 如何解决跨域

2.1 JSONP

  1. JSONP是什么

    JSONP (JSON with Padding),是一个非官方的跨域解决方案,纯粹凭借程序员的聪明才智开发出来,只支持get请求

  2. JSONP 怎么工作的?

    在网页有一些标签天生具有跨域能力,比如:img, link, iframe, script

    JSONP就是利用script标签的跨域能力来发送请求的

  3. JSONP的使用

    • 动态的创建一个script标签
    var script = document.createElement("script");
    
    • 设置script的src,设置回调函数
    script.src = "http://locallhost:3000/textAJAX?callback=abc"
    

2.2 JSONP原理

我们本地写的以后缀为.html结尾的链接是以file协议的

script文件生成的链接是http协议的,因此script标签本身支持跨域能力

我们可以借助open with live server 找到js文件,以http协议的链接

<body>
    <div class="root"></div>
    <script>
        function handleData(data) {
        	let root = document.querySelector('.root')
        	// console.log(root);
        	root.innerText = data.msg
		}
    </script>
    <script src="http://127.0.0.1:5500/04%E5%90%8C%E6%BA%90/app.js"></script>
</body>

app.js

const data = {
    name: '尚硅谷atguigu'
};

handle(data);

QQ截图20220212150233

当参数为String,该方法将设置Content-Type为“text / html”:

res.send('<p>some html</p>');

当参数是Array或Object,Express以JSON表示响应:

res.send({ user: 'tobi' });
res.send([1,2,3])
  1. 参数类型的区别:
  • res.end() 参数为: a Buffer object / a String
  • res.send() 参数为: a Buffer object / a String / an object / an Array

​ 2.发送服务器内容不同

  • res.end() 只接受服务器响应数据,如果是中文则会乱码
  • res.send() 发送给服务端时,会自动发送更多的响应报文头,其中包括 Content-Tpye: text/html; charset=uft-8,所以中文不会乱码
<body>
    <div id="result"></div>
    <script>
        //处理数据
        function handle(data) {
            //获取 result 元素
            const result = document.getElementById('result');
            result.innerHTML = data.name;
        }
    </script>
    <!-- <script src="http://127.0.0.1:5500/%E8%AF%BE%E5%A0%82/%E4%BB%A3%E7%A0%81/7-%E8%B7%A8%E5%9F%9F/2-JSONP/js/app.js"></script> -->
    <script src="http://127.0.0.1:8000/jsonp-server"></script>
</body>

需要注意的是,不需要再去将str转为对象,如果下面直接使用对象传过去,会自动帮我们调用toString方法

??那不用在去处理将它转为对象吗??

//jsonp服务
app.all('/jsonp-server',(request, response) => {
    // response.send('console.log("hello jsonp")');
    const data = {
        name: '尚硅谷atguigu'
    };
    //将数据转化为字符串
    let str = JSON.stringify(data);
    //返回结果
    //end不会加响应头
    // 使用了es6的插值语法
    response.end(`handle(${str})`);
});

注意:end函数中的符号为斜点,不是单引号

可以理解,返回的为js语句。同步给了script标签,在这个过程,它执行了脚本,调用了handle函数。

个人理解:${}是将函数代码先转换成js引擎可以识别的字符串,然后js引擎将其再转化为javascript语言规范的代码

2.3 jsonp实战

需求:当输入用户名以后,在失去焦点的时候向服务器发送请求,检测用户名是否已经存在

<body>
    用户名: <input type="text" id="username">
    <p></p>
    <script>
        //获取 input 元素
        const input = document.querySelector('input');
        const p = document.querySelector('p');
        
        //声明 handle 函数
        function handle(data){
            input.style.border = "solid 1px #f00";
            //修改 p 标签的提示文本
            p.innerHTML = data.msg;
        }

        //绑定事件
        input.onblur = function(){
            //获取用户的输入值
            let username = this.value;
            //向服务器端发送请求 检测用户名是否存在
            //1. 创建 script 标签
            const script = document.createElement('script');
            //2. 设置标签的 src 属性
            script.src = 'http://127.0.0.1:8000/check-username';
            //3. 将 script 插入到文档中
            document.body.appendChild(script);
        }
    </script>
</body>
//用户名检测是否存在
// 这里支持get和all
app.all('/check-username',(request, response) => {
    // response.send('console.log("hello jsonp")');
    const data = {
        exist: 1,
        msg: '用户名已经存在'
    };
    //将数据转化为字符串
    let str = JSON.stringify(data);
    //返回结果
    response.end(`handle(${str})`);
});

3、 CORS

推荐阅读:

  1. CORS是什么?

    CORS (Cross-Origin Resource Sharing), 跨域资源共享。CORS 是官方的跨域解决方案,它的特点是不需要在客户端做任何特殊的操作,完全在服务器中进行处理,支持 get 和 post 等请求。跨域资源共享标准新增了一组 HTTP 首部字段(响应头),允许服务器声明哪些源站通过浏览器有权限访问哪些资源

  2. CORS怎么工作的?

    CORS 是通过设置一个响应头来告诉浏览器,该请求允许跨域,浏览器收到该响应以后就会对响应放行。

  3. CORS 的使用

    主要是服务端的设置:

    rounter.get("/testAJAX",function(req, res){
        // 允许所有端口网页访问
    	response.setHeader("Access-Control-Allow-Origin", "*");
        // response.setHeader("Access-Control-Allow-Origin", "http://127.0.0.1:5500");
    })
    

    平时的open with liver serve插件 就是默认开启了一个5500端口的服务器

  4. 还可以设置其他的响应头,以及其它信息等

    参见mdn文档 cros

    app.all('/cors-server', (request, response)=>{
        //设置响应头
        response.setHeader("Access-Control-Allow-Origin", "*");
        
        // 允许自定义头信息数据
        response.setHeader("Access-Control-Allow-Headers", '*');
        
        // 允许自定义请求方法
        response.setHeader("Access-Control-Allow-Method", '*');
        
        // response.setHeader("Access-Control-Allow-Origin", "http://127.0.0.1:5500");
        response.send('hello CORS');
    });
    
posted @ 2022-02-13 13:14  李小晚  阅读(36)  评论(0编辑  收藏  举报