Ajax——CORS跨域共享

一、同源政策

同源政策的目的

二、CORS:跨域资源共享

 

CORS:跨域资源共享(Cross-origin resource sharing),它允许浏览器向跨域服务器发送ajax请求,克服了ajax只能同源使用的限制

 

当浏览器发现请求是跨域请求时,会在自动请求头加入origin字段,服务器端会根据origin字段的值来决定是否同意这次请求

如果服务器端同意这次请求,就会在响应头中加入 Access-Control-Access-Origin字段

origin:http://localhost:3000
 Access-Control-Allow-Origin: 'http://localhost:3000'
 Access-Control-Allow-Origin: '*'    // *代表允许所有客户端访问这个服务器端

 

 2.1、在服务器端设置可以跨域访问的路由地址

准备两个服务器s1和s2,在s1中写入下面的代码,点击按钮发起请求

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <button id="btn">点我发送请求</button>
    <script src="./js/ajax.js"></script>
    <script>
        // 获取按钮
        var btn = document.getElementById('btn');
        // 为按钮添加点击事件
        btn.onclick =function(){
            ajax({
                type:'get',
                url:'http://localhost:3001/cross',
                success:function(data){
                    console.log(data);
                    
                }
            })
        }
    </script>
</body>
</html>

 

 

在s2服务器的app.js中写入下面的代码

app.get('/cross',(req,res)=>{
    // 1.允许哪些客户端访问
    // * 代表允许所有客户端访问我
    res.header('Access-Control-Allow-Origin', '*')
    // 2. 允许客户端使用哪些请求方法访问我
    res.header('Access-Control-Allow-Methods', 'get,post')
    res.send('ok')
})

 

可以在控制台中看到输出了OK

但是当请求比较多的时候,我们没有办法筛选哪些可以访问哪些不能访问

改写成下面的样子

//拦截所有请求
app.use((req,res,next)=>{
    // 1.允许哪些客户端访问
    // * 代表允许所有客户端访问我
    res.header('Access-Control-Allow-Origin', '*')
    // 2. 允许客户端使用哪些请求方法访问我
    res.header('Access-Control-Allow-Methods', 'get,post')
    next();
})
app.get(
'/cross',(req,res)=>{ res.send('ok') })

 

2.2、服务器端解决跨域

设置多个服务器,由于服务器互相访问是没有同原限制的,借助这个解决跨域

A客户端访问A服务器端

使用request模块实现A服务器端访问B服务器端的数据

B服务器端响应数据给A服务器端,再响应给A客户端

<body>
    <button id="btn">点我发送请求</button>
    <script src="./js/ajax.js"></script>
    <script>
        // 获取按钮
        var btn = document.getElementById('btn');
        // 为按钮添加点击事件
        btn.onclick =function(){
            ajax({
                type:'get',
                url:'http://localhost:3000/server',
                success:function(data){
                    console.log(data);
                    
                }
            })
        }
    </script>
</body>
// 向其他服务器端请求数据的模块,服务器端是没有同源政策的限制的,可以向任何服务器发送请求
const request = require('request');

// 第一个参数是其他服务器端的地址,第二个参数是一个回调函数,当请求返回数据的时候,这个回调函数开始执行
// 回调函数第一个参数err:如果请求发生错误会返回错误信息,否则返回null
// response:是一个对象,
// body: 返回的是响应内容
app.get('/server', (req, res) => {
    request('http://localhost:3001/cross', (err, response, body) => {
        res.send(body)
    })
})

 

2.3、cookie跨域问题

 实现客户端与服务器端识别身份的一种技术

客户端第一次访问服务器端的时候,服务器端响应的时候会发送一个身份证,也就是cookie,这个cookie就会存储在客户端的浏览器中,等客户端下一次再次访问这个服务器端的时候,cookie会随着请求被自动发送到服务器端,服务器端拿到cookie就知道客户端是谁了

但是一旦涉及到跨域,出于安全考虑,防止信息被窃取,cookie就不会随着请求被发送到服务器端了,也就是说,在跨域的情况下发起的ajax请求,是不会携带cookie信息的

解决这个问题我们需要设置如下属性:

Access-Control-Allow-Credentials:true  //允许客户端发送请求时携带cookie
ajax对象下面的withCredentials属性,默认值为false
 
案例:
有一个登录模块:
<div class="container">
        <form id="loginForm">
            <div class="form-group">
                <label>用户名</label>
                <input type="text" name="username" class="form-control" placeholder="请输入用户名">
            </div>
            <div class="form-group">
                <label>密码</label>
                <input type="password" name="password" class="form-control" placeholder="请输入用密码">
            </div>
            <input type="button" class="btn btn-default" value="登录" id="loginBtn">
            <input type="button" class="btn btn-default" value="检测用户登录状态" id="checkLogin">
        </form>
    </div>

第一步:获取登录按钮和检测登录按钮一级登录表单,使用formData

第二步:添加点击事件,点击按钮发送请求

第三步:在客户端设置属性,由于是跨域请求,我们需要设置withCredentials属性的值

// 获取登录按钮
    var loginBtn = document.getElementById('loginBtn');
    // 获取检测登录状态按钮
    var checkLogin = document.getElementById('checkLogin');
    // 获取登录表单
    var loginForm = document.getElementById('loginForm');
    // 为登录按钮添加点击事件
    loginBtn.onclick = function(){
        // 将HTML表单转换为formData表单对象
        var formData = new FormData(loginForm);
        // 创建ajax对象
        var xhr = new XMLHttpRequest();
        // 对ajax对象进行配置
        xhr.open('post','http://localhost:3001/login');
        // 当发送跨域请求时,携带cookie信息
        xhr.withCredentials = true;
        //  发送请求并传递请求参数
        xhr.send(formData)
        // 监听服务器端的响应
        xhr.onload = function(){
            console.log(xhr.responseText);
            
        }

    }

    // 当检测登录按钮被点击时
    checkLogin.onclick = function(){
        // 创建ajax对象
        var xhr = new XMLHttpRequest();
        // 对ajax对象进行配置
        xhr.open('get','http://localhost:3001/checkLogin');
        // 当发送跨域请求时,携带cookie信息
        xhr.withCredentials = true;
        //  发送请求并传递请求参数
        xhr.send()
        // 监听服务器端的响应
        xhr.onload = function(){
            console.log(xhr.responseText);
            
        }
    }

 

 第四步:在服务器端设置相关属性

// 拦截所有请求
app.use((req, res, next) => {
    // 1.允许哪些客户端访问我
    // * 代表允许所有的客户端访问我
    // 注意:如果跨域请求中涉及到cookie信息传递,值不可以为*号 比如是具体的域名信息
    res.header('Access-Control-Allow-Origin', 'http://localhost:3000')
    // 2.允许客户端使用哪些请求方法访问我
    res.header('Access-Control-Allow-Methods', 'get,post')
    // 允许客户端发送跨域请求时携带cookie信息
    res.header('Access-Control-Allow-Credentials', true);
    next();
});

 

posted @ 2020-05-01 20:19  ccv2  阅读(321)  评论(0编辑  收藏  举报