跨域请求的处理-jsonp

同源策略

同源策略是浏览器的一种安全策略。
同源策略:即 网页的url 和 该网页请求的url 的协议、域名、端口必须保持一致。
协议、域名、端口必须保持一致就是说网页的加载服务器和页面请求的请求服务器是同一个服务器的同一个服务。
ajax默认支持同源策略
图示理解:
在这里插入图片描述
在url上表示为:
网页的url是 http://a.com:8080,那么网页请求的url也必须是 http://a.com:8080

eg:同源策略
html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>首页</title>
</head>
<body>
    <h2>首页</h2>
    <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>

server.js

const {
    
     response, request } = require('express');
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('服务已启动……');
    
})

输出:
在这里插入图片描述

跨域

违背同源策略就是跨域。
即如果网页请求的url 和 网页的url 的协议、域名、端口任意一项不同就是跨域。
在这里插入图片描述

跨域的解决

jsonp

jsonp定义

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

jsonp工作方式

在网页有一些标签天生具有跨域能力,比如: img link iframe script.
JSONP就是利用script标签的跨域能力来发送请求的。

  • script标签本身就具有跨域特性。
    eg:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.27.2/axios.js"></script>
</head>
<body>
    <div class="container">
        <h2 class="page-header">jQuery发送AJAX请求</h2>
        <button class="btn btn-primary">GET</button>
        <button class="btn btn-danger">POST</button>
        <button class="btn btn-info">通用型方法ajax</button>
    </div>
    <script>
        const btns =document.querySelectorAll('button')
        axios.defaults.baseURL = 'http://127.0.0.1:8000'
        btns[0].onclick =function(){
      
      
        // get请求
        axios.get('/axios-server',{
      
      
            // 参数:
            params:{
      
      
                id:100,
                vip:7
            },
            // 请求头
            headers:{
      
      
                name:'yang',
                // age:20
            }
        }).then(value =>{
      
      
            // 响应体结果
            console.log(value)    
        })
        }

        btns[1].onclick =function(){
      
      
        // get请求
        axios.post('/axios-server',
            {
      
      // 请求体
                username:'admin',
                password:'admin'
            },{
      
      
            // 参数:
            params:{
      
      
                id:200,
                vip:9
            },
            // 请求头
            headers:{
      
      
                heigth:200,
                width:200
            }
        })
        }
        
        btns[2].onclick = function (){
      
      
           axios({
      
      
            //    请求方法:
            method:'POST',
            //    url
            url:'/axios-server',
            // 参数
            params:{
      
      
                vip:10,
                level:30
            },
            // 请求头
            headers:{
      
      
                heigth:200,
                width:200
            },
            // 请求体
            data:{
      
      
                username:'admin',
                password:'admin'
            }

           }).then(response=>{
      
      
            //    console.log(response)
               //响应状态码
                console.log(response.status);
                //响应状态字符串
                console.log(response.statusText);
                //响应头信息
                console.log(response.headers);
                //响应体
                console.log(response.data);
           })
        }
    </script>
    
</body>
</html>

<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.27.2/axios.js"></script>引入的是远端内容,而网页请求url是:http://127.0.0.1:8000,这是跨域请求,但是能正常访问。

  • jspon原理解析
    利用script标签的跨域能力:
    原理.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>jsonp原理</title>
    <style>
        #result{
      
      
            width: 300px;
            height: 100px;
            border:solid 1px darkcyan;
        }
    </style>
</head>
<body>
    <div id='result'></div>
    <script>
        function handle(data) {
      
      
            // 获取result
            const result = document.getElementById('result');
            result.innerHTML = data.name;
        }
    </script>
    <script type='text/javascript' src='http://localhost:8080/jsonp/app.js'></script>
</body>
</html>

app.js

const data = {
    
    
    name:'@yang'
}

handle(data);

原理.html会向app.js发送请求,app.js的响应结果是app.js的内容。
在这里插入图片描述

jsonp的使用

ajax默认情况下是不可以进行跨域请求的,我们可以使用jsonp请求来实现跨域请求:

  • 使用script标签进行服务器请求,在实际开发中jspon就是通过动态创建script标签来实现跨域请求的
  • script的返回结果需要是js能够解析的语句,所以jsonp请求的响应结果一般是一个函数调用,而函数调用的实参一般是我们想要返回给前端的数据。(该函数应该是前端js定义好的函数)

eg:
html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>jsonp原理</title>
    <style>
        #result{
      
      
            width: 300px;
            height: 100px;
            border:solid 1px darkcyan;
        }
    </style>
</head>
<body>
    <div id='result'></div>
    <script>
        function handle(data) {
      
      
            // 获取result
            const result = document.getElementById('result');
            result.innerHTML = data.name;
        }
    </script>
    <script type='text/javascript' src='http://127.0.0.1:8000/jsonp-server'></script>
</body>
</html>

server.js:

// 1.引入express
const express = require('express');
// 2.创建应用对象
const app = express();
// 3.创建路由规则
// jsonp服务
app.all('/jsonp-server', (request, response) => {
    
    
    const data = {
    
    
        name:'hello yang'
    }
    let str = JSON.stringify(data)
    response.end(`handle(${
      
      str})`)
})
// 4.监听端口启动服务
app.listen(8000, () => {
    
    
    console.log('服务已经启动,8000端口监听中……')
})

在这里插入图片描述
输出:
在这里插入图片描述

jsonp实现跨域请求实现——动态请求

在时机使用jsonp的时候我们不知道什么时候会调用jsonp实现跨域请求,一般情况下会绑定按钮,当点击按钮的时候实现跨域请求。而jsopn是通过script标签实现的,所以在啊hi及开发中一般使用动态创建script标签来实现跨域请求。

使用jsonp的步骤:

//  1. 创建script标签
const script = document.createElement('script')
//  2. 设置script的src
script.src = 'http://127.0.0.1:8000/check-username'
// 3.将script插入到文档中,插入到body最后
document.body.appendChild(script);

eg:需求:输入框失去焦点的时候向服务器发送请求,返回应户名已存在。

html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    用户名: <input type="text" id='username'>
    <p></p>
    <script>
        const input = document.querySelector('input');
        const p = document.querySelector('p')
        function handle(data){
      
      
           input.style.border = 'solid 1px #f00'
           p.innerHTML= data.msg
        }

        input.onblur = function (){
      
      
           let username = this.value
        //    向服务端发送请求
        //  1. 创建script标签
        const script = document.createElement('script')
        //  2. 设置script的src
        script.src = 'http://127.0.0.1:8000/check-username'
        // 3.将script插入到文档中,插入到body最后
        document.body.appendChild(script);
        }
    </script>
</body>
</html>

server.js

// 1.引入express
const express = require('express');
// 2.创建应用对象
const app = express();
// 3.创建路由规则
// 用户名检测
app.all('/check-username', (request, response) => {
    
    
    const data = {
    
    
        exist: 1,
        msg:'用户名已存在'
    }
    let str = JSON.stringify(data)
    response.end(`handle(${
      
      str})`)
})
// 4.监听端口启动服务
app.listen(8000, () => {
    
    
    console.log('服务已经启动,8000端口监听中……')
})

运行结果:
在这里插入图片描述

jQuery发送jsonp请求

格式:$.getJSON('url?callback=?',function (data){})
callback=?是固定写法,而且callback在实际请求中是有参数的。
eg:
在这里插入图片描述
实例:
html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script crossorigin="anonymous" src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
    <style>
        #result{
      
      
            width: 300px;
            height: 100px;
            border:solid 1px #089;
        }
    </style>
</head>
<body>
    <button>点击发送jsonp请求</button>
    <div id="result">

    </div>
    <script>
        $('button').eq(0).click(function (){
      
      
           $.getJSON('http://127.0.0.1:8000/jquery-jsonp-server?callback=?',function (data){
      
      
              $('#result').html(`
              名称:${ 
        data.name}<br>
              城市:${ 
        data.city}
              `)
           })
        })
    </script>
</body>
</html>

js:

// 1.引入express
const express = require('express');
// 2.创建应用对象
const app = express();
// 3.创建路由规则
// jquery发送jsonp
app.all('/jquery-jsonp-server', (request, response) => {
    
    
    const data = {
    
    
        name: 'yang',
        city:'beijing'
    }
    // 将数据转换成字符串
    let str = JSON.stringify(data)
    // 接收callback参数
    let cb = request.query.callback;

    // 返回结果
    response.end(`${
      
      cb}(${
      
      str})`)
})
// 4.监听端口启动服务
app.listen(8000, () => {
    
    
    console.log('服务已经启动,8000端口监听中……')
})

在这里插入图片描述

CORS解决跨域请求

CORS是什么?

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

CORS怎么工作的?

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

使用cors实现ajax的跨域请求

如果不使用cors解决跨域请求ajax会报如下错误:
在这里插入图片描述
使用cors实现ajax的跨域请求只需要在服务器端添加如下语句
response.setHeader('Access-Control-Allow-Origin','*');
设置响应头 设置允许跨越,*代表可以跨域到所有网页。

响应头不止一种们可以在如下网页进行查看:
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS

一般情况下我们设置下面3种:

    // 设置响应头 设置允许跨越,*代表可以跨域到所有网页
    response.setHeader('Access-Control-Allow-Origin', '*');
    // 设置允许自定义请求头信息
    response.setHeader('Access-Control-Allow-Headers', '*');
    // 设允许所有请求类型
    response.setHeader('Access-Control-Allow-Method','*');

eg:
html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</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()
        // 处理结果
        x.onreadystatechange = function (){
      
      
           if(x.readyState === 4){
      
      
               if(x.status>=200 && x.status<300){
      
      
                   console.log(x.response);  
               }
           }
        }
    }

    </script>
</body>
</html>

server.js

// 1.引入express
const express = require('express');
// 2.创建应用对象
const app = express();
// 3.创建路由规则
// cors-server
// cors-server
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.send('Hello CORS')
})
// 4.监听端口启动服务
app.listen(8000, () => {
    
    
    console.log('服务已经启动,8000端口监听中……')
})

在这里插入图片描述

补充:所有响应头种类见这里

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/mantou_riji/article/details/124767753