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
<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(); });