【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端口监听中......");
});
相关推荐
kyriewen7 小时前
写组件文档写到吐?我用AI自动生成Storybook,同事以后直接抄
前端·javascript·面试
五点六六六8 小时前
你敢信这是非Native页面写出来的渐变效果吗🌝(底层原理解析
前端·javascript·面试
吃西瓜的年年8 小时前
TypeScript
javascript·ubuntu·typescript
熊猫_豆豆11 小时前
一个模拟四轴飞行器在随机气流扰动下悬停飞行的交互式3D仿真网页,包含飞行器建模与PID控制算法
javascript·3d·html·四轴无人机模拟飞行
来恩100312 小时前
jQuery选择器
前端·javascript·jquery
前端繁华如梦12 小时前
树上挂苹果还是挂玻璃球?Three.js 程序化果实的完整实现指南
前端·javascript
CDwenhuohuo13 小时前
优惠券组件直接用 uview plus
前端·javascript·vue.js
川冰ICE14 小时前
TypeScript装饰器与元编程实战
前端·javascript·typescript
AI砖家14 小时前
Vue3组件传参大全,各种传参方式的对比
前端·javascript·vue.js
希望永不加班14 小时前
var局部变量类型推断的利弊
java·服务器·前端·javascript·html