方法一 Jsonp 的方式来解决
原理: 利用 script 标签不受同源政策的影响,向服务器端发送请求,返回的是全局函数。
注: 这只是部分代码, 是没有服务器端代码的
<button id="btn1">点我发送请求</button>
<button id="btn2">点我发送请求</button>
<script type="text/javascript">
// 获取按钮
var btn1 = document.getElementById('btn1');
var btn2 = document.getElementById('btn2');
// 为按钮添加点击事件
btn1.onclick = function () {
// jsonp 是我们封装的函数,调用函数来 发送请求
jsonp({
url: 'http://localhost:3001/better',
success: function (data) {
console.log(123);
console.log(data);
},
data: {
name: 'wqx',
age: 18
}
});
}
btn2.onclick = function () {
// jsonp 是我们封装的函数,调用函数来 发送请求
jsonp({
url: 'http://localhost:3001/better',
success: function (data) {
console.log(666);
console.log(data);
}
});
}
function jsonp(options) {
// 动态创建 script 标签
let script = document.createElement('script');
// 拼接还可以用数组来完成
// let arr = [];
// for (let attr in options.data) {
// arr.push(`${attr} = ${options.data[attr]}`);
// }
// 定义一个空的字符串
let params = '';
// 循环传递过来的 data 数据
for (let attr in options.data) {
params += '&' + attr + '=' + options.data[attr];
}
// 生成随机名字, 名字不能相同,不然后续的请求会覆盖前面的请求
let fnName = 'myjson' + Math.random().toString().replace('.', '');
// 点后面不能跟变量,所以这里用的就是括号
// 又因为是全局变量,所以必须要在window下面挂载属性
window[fnName] = options.success;
// 拼接参数
script.src = options.url + '?callback=' + fnName + params;
document.body.appendChild(script);
script.onload = function () {
document.body.removeChild(script);
}
}
</script>
方法二 CORS 解决方法 (主流的解决方式)
前端代码不需要做任何改变
CORS 主要都是后端来解决 跨域 所遇到的问题
// 这些都是后端需要的配置
// 拦截所有请求
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();
});
方法三 同源政策不会影响服务器
原理: 由一号服务器的 客户端 向一号服务器发出请求,在由 一号服务器 向二号服务器发送请求,这样就解决了同源限制的影响
一号 客户端代码
<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>
一号 服务器 后端代码
// 向其他服务器端请求数据的模块
const request = require('request');
app.get('/server', (req, res) => {
request('http://localhost:3001/cross', (err, response, body) => {
res.send(body);
})
});
二号 服务器 后端代码
// 拦截所有请求
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();
});
app.get('/cross', (req, res) => {
res.send('ok')
});
方法四 withCredentials 解决跨域登录
客户端代码
<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>
<script type="text/javascript">
// 获取登录按钮
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);
}
}
</script>
后端代码
app.post('/login', (req, res) => {
// 创建表单解析对象
var form = formidable.IncomingForm();
// 解析表单
form.parse(req, (err, fields, file) => {
// 接收客户端传递过来的用户名和密码
const { username, password } = fields;
// 用户名密码比对
if (username == 'itheima' && password == '123456') {
// 设置session
req.session.isLogin = true;
res.send({ message: '登录成功' });
} else {
res.send({ message: '登录失败, 用户名或密码错误' });
}
})
});
app.get('/checkLogin', (req, res) => {
// 判断用户是否处于登录状态
if (req.session.isLogin) {
res.send({ message: '处于登录状态' })
} else {
res.send({ message: '处于未登录状态' })
}
});