【Ajax】跨域

文章目录

  • [1 同源策略](#1 同源策略)
    • [1.1 index.html](#1.1 index.html)
    • [1.2 server.js](#1.2 server.js)
  • [2 如何解决跨域](#2 如何解决跨域)
    • [2.1 JSONP](#2.1 JSONP)
      • [2.1.1 JSONP 原理](#2.1.1 JSONP 原理)
      • [2.1.2 JSONP 实践](#2.1.2 JSONP 实践)
      • [2.1.3 jQuery 中的 JSONP](#2.1.3 jQuery 中的 JSONP)
    • [2.2 CORS](#2.2 CORS)
      • [2.2.1 CORS实践](#2.2.1 CORS实践)
  • [3 server.js](#3 server.js)

1 同源策略

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

同源:协议、域名、端口号 必须完全相同。

违背同源策略就是跨域。

1.1 index.html

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>首页</title>
</head>
<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>
</html>

1.2 server.js

js 复制代码
const express = require('express');

const app = express();

app.get('/home', (request, response)=>{
    //响应一个页面
    response.sendFile(__dirname + '/index.html');
});

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

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

2 如何解决跨域

2.1 JSONP

  • JSONP 是什么?
    JSONP(JSON with Padding),是一个非官方的跨域解决方案,只支持 get 请求。
  • JSONP 怎么工作的?
    在网页中,有一些标签天生具有跨域能力,比如:img、link、iframe、script,JSONP 就是利用 script 标签的跨域能力来发送请求的。
  • JSONP 的使用
    1. 动态的创建一个 script 标签

      html 复制代码
      var script = document.createElement("script");
    2. 设置 script 的 src,设置回调函数

      html 复制代码
      script.src = "http://localhost:3000/testAJAX?callback=abc";
      function abc(data) {
      	alert(data.name);
      };
    3. 将 script 添加到 body 中

      html 复制代码
      document.body.appendChild(script);
    4. 服务器中路由的处理

      js 复制代码
      router.get("/testAJAX", function (req, res) {
      	console.log("收到请求");
      	var callback = req.query.callback;
      	var obj = {
      		name:"孙悟空", 
      		age:18
      	}
      	res.send(callback+"("+JSON.stringify(obj)+")");
      });

2.1.1 JSONP 原理

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>原理演示</title>
    <style>
        #result {
            width: 300px;
            height: 100px;
            border: solid 1px #78a;
        }
    </style>
</head>

<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>
</html>
js 复制代码
const data = {
    name: '尚硅谷atguigu'
};

handle(data);

2.1.2 JSONP 实践

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>案例</title>
</head>
<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>
</html>

2.1.3 jQuery 中的 JSONP

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>jQuery-jsonp</title>
    <style>
        #result{
            width:300px;
            height:100px;
            border:solid 1px #089;
        }
    </style>
    <script crossorigin="anonymous" src='https://cdn.bootcss.com/jquery/3.5.0/jquery.min.js'></script>
</head>
<body>
    <button>点击发送 jsonp 请求</button>
    <div id="result">

    </div>
    <script>
        $('button').eq(0).click(function(){
            //固定写法:callback=?,?实际上是一串数字-request.query.callback
            $.getJSON('http://127.0.0.1:8000/jquery-jsonp-server?callback=?', function(data){
                $('#result').html(`
                    名称: ${data.name}<br>
                    校区: ${data.city}
                `)
            });
        });
    </script>
</body>
</html>

2.2 CORS

文档:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS

  • CORS 是什么?

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

  • CORS 怎么工作的?

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

  • CORS 的使用

    主要是服务器端的设置:

    javascript 复制代码
    router.get("/testAJAX", function (req, res) {
    	//通过 res 来设置响应头,来允许跨域请求
    	//res.set("Access-Control-Allow-Origin", "http://127.0.0.1:3000");
    	res.set("Access-Control-Allow-Origin", "*");
    	res.send("testAJAX 返回的响应");
    });

2.2.1 CORS实践

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>CORS</title>
    <style>
        #result{
            width:200px;
            height:100px;
            border:solid 1px #90b;
        }
    </style>
</head>
<body>
    <button>发送请求</button>
    <div id="result"></div>
    <script>
        const btn = document.querySelector('button');

        btn.onclick = function(){
            //1. 创建对象
            const x = new XMLHttpRequest();
            //2. 初始化设置
            x.open("GET", "http://127.0.0.1:8000/cors-server");
            //3. 发送
            x.send();
            //4. 绑定事件
            x.onreadystatechange = function(){
                if(x.readyState === 4){
                    if(x.status >= 200 && x.status < 300){
                        //输出响应体
                        console.log(x.response);
                    }
                }
            }
        }
    </script>
</body>
</html>

3 server.js

js 复制代码
//1. 引入express
const express = require('express');

//2. 创建应用对象
const app = express();

//3. 创建路由规则
//request:对请求报文的封装
//response:对响应报文的封装
app.get('/server', (request, response) => {
    //设置响应头,设置允许跨域
    response.setHeader('Acess-Control-Allow-Origin', '*');
    //设置响应体
    response.send('hello Ajax');
});

//all:可以接受任意类型的请求
app.all('/server', (request, response) => {
    //设置响应头,设置允许跨域
    response.setHeader('Acess-Control-Allow-Origin', '*');
    //响应头,*:所有类型的头信息都可以接受
    response.setHeader('Acess-Control-Allow-Headers', '*');
    //设置响应体
    response.send('hello Ajax POST');
});

//JSON 响应
app.all('/json-server', (request, response) => {
    //设置响应头,设置允许跨域
    response.setHeader('Acess-Control-Allow-Origin', '*');
    //响应头
    response.setHeader('Acess-Control-Allow-Headers', '*')
    //响应一个数据
    const data = {
        name: 'atguigu'
    };
    //对对象进行字符串转换
    let str = JSON.stringify(data);
    //设置响应体
    response.send(str);
});

//针对IE缓存
app.get('/ie', (request, response) => {
    //设置响应头,设置允许跨域
    response.setHeader('Acess-Control-Allow-Origin', '*');
    //设置响应体
    response.send('hello IE');
});

//延时响应
app.all('/delay', (request, response) => {
    //设置响应头,设置允许跨域
    response.setHeader('Acess-Control-Allow-Origin', '*');
    response.setHeader('Acess-Control-Allow-Headers', '*');
    setTimeout(() => {
        //设置响应体
        response.send('延时响应');
    }, 3000);
});

//jQuery 服务
app.all('/jquery-server', (request, response) => {
    //设置响应头,设置允许跨域
    response.setHeader('Acess-Control-Allow-Origin', '*');
    response.setHeader('Acess-Control-Allow-Headers', '*');
    const data = {
        name: '尚硅谷'
    };
    response.send(JSON.stringify(data));
});

//axios 服务
app.all('/axios-server', (request, response) => {
    //设置响应头,设置允许跨域
    response.setHeader('Acess-Control-Allow-Origin', '*');
    response.setHeader('Acess-Control-Allow-Headers', '*');
    const data = {
        name: '尚硅谷'
    };
    response.send(JSON.stringify(data));
});

//fetch 服务
app.all('/fetch-server', (request, response) => {
    //设置响应头,设置允许跨域
    response.setHeader('Acess-Control-Allow-Origin', '*');
    response.setHeader('Acess-Control-Allow-Headers', '*');
    const data = {
        name: '尚硅谷'
    };
    response.send(JSON.stringify(data));
});

//jsonp 服务
app.all('/jsonp-server', (request, response) => {
    //response.send('console.log("hello jsonp")');
    const data = {
        name: '尚硅谷atguigu'
    };
    //将数据转化为字符串
    let str = JSON.stringify(data);
    //返回结果
    response.end(`handle(${str})`);//返回结果是一个函数调用,函数的实参就是想给客户端返回的结果数据,函数必须提前声明。
});

//用户名检测是否存在
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})`);
});

//jquery-jsonp
app.all('/query-jsonp-server', (request, response) => {
    //response.send('console.log("hello jsonp")');
    const data = {
        name: '尚硅谷',
        city: ['北京', '上海', '深圳']
    };
    //将数据转化为字符串
    let str = JSON.stringify(data);
    //接收callback参数
    let cb = request.query.callback;
    //返回结果
    response.end(`${cb}${str}`);
});

//cors
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');
});

//4. 监听窗口启动服务
app.listen(8000, () => {
    console.log("服务已经启动,8000端口监听中......");
});
相关推荐
xptwop1 小时前
05-ES6
前端·javascript·es6
Heo1 小时前
调用通义千问大模型实现流式对话
前端·javascript·后端
前端小巷子2 小时前
深入 npm 模块安装机制
前端·javascript·面试
深职第一突破口喜羊羊3 小时前
记一次electron开发插件市场遇到的问题
javascript·electron
cypking3 小时前
electron中IPC 渲染进程与主进程通信方法解析
前端·javascript·electron
西陵3 小时前
Nx带来极致的前端开发体验——借助playground开发提效
前端·javascript·架构
江城开朗的豌豆4 小时前
Element UI动态组件样式修改小妙招,轻松拿捏!
前端·javascript·vue.js
float_六七4 小时前
JavaScript:现代Web开发的核心动力
开发语言·前端·javascript
zhaoyang03014 小时前
vue3笔记(2)自用
前端·javascript·笔记
UrbanJazzerati5 小时前
JavaScript Promise完整指南
javascript