本文所有代码都经过测试(vcCode+nodejs+chrome),请自行安装依赖,如有错误,请指点一二
碍于浏览器的同源策略,前端需要获取后端的数据时,需要进行跨域处理,什么情况下需要跨域?
假如你的URL为 http://baidu.com/dist/index.html ,
http://baidu.com/list/index.html 访问成功
http://baidu.com:81/dist/index.html 访问失败(端口不一样,默认为80端口)
https://baidu.com/dist/index.html 访问失败(协议不一样)
http://sougou.com/dist/index.html 访问失败(主机不一样)
如果URL非同源,会有三种应为受到限制:
(1)Cookie、localStorage、IndexDB无法读取
(2)DOM无法获取
(3)AJAX请求无法处理(注意前端是可以发送AJAX请求的,无论以什么格式发送,后端接收到的都是options类型)
未做跨域处理时
前端代码
<script>
// 不跨域
var xhr=new XMLHttpRequest();
xhr.onreadystatechange=function(){
if(xhr.readyState == 4 && xhr.status === 200){
console.log(xhr.responseText)
}
}
xhr.open('GET','http://localhost:3002',true)
xhr.send()
</script>
后端代码
const express =require('express')
const app =express()
app.get('/',function(req,res){
res.json({
name:'我是谁'
})
})
app.listen(3002)
console.log('http://localhost:3002')
浏览器报错
借助script标签进行跨域:
因为script标签不受同源策略影响,可以使用script标签引入任何URL地址的资源,jsonp也是利用了这个原理,在前端定义一个函数,通过script标签把函数添加到URL后面,作为请求体发送给后端,后端检测到函数体的存在,定义一个函数,返回一个script代码。调用前端定义的函数,把数据传入到函数中
前端代码:
<script>
function getData (data){
console.log(data)
}
</script>
<script src="http://localhost:3001/?_callBack=getData"></script>
后端代码:
const express =require('express')
const app=express()
app.get('/',function(req,res,next){
var _callBack=req.query._callBack;
var responseData={
say:'我跨域回来了',
}
if(_callBack){
res.type('text/javascript')
// 注意不要使用ES6的``操作符拼接,``操作符拼接完的字符前默认添加有加号,相当于与前面的字符串拼接,并不是我们想要的函数
// res.send(`${_callBack}+(${JSON.stringify(responseData)})`)
res.send(_callBack + "(" + JSON.stringify(responseData) + ")")
}else{
res.json(responseData)
}
})
app.listen(3001)
console.log('http://localhost:3001')
浏览器结果:
获取到后端传过来的数据,跨域成功
注意:使用jsonp或者是使用script标签方法进行跨域,只能使用GET进行访问,因为需要在请求体中添加接收函数,回调函数的方法必须是全局的
使用CROS进行跨域(只需要配置服务器端即可)
前端代码:(正常请求)
<script>
var xhr=new XMLHttpRequest()
xhr.onreadystatechange=function(){
if(xhr.readyState ===4 && xhr.status ===200){
console.log(xhr.responseText)
}
}
xhr.open('GET','http://localhost:3001',true)
xhr.send()
</script>
后端代码:
const express=require('express')
const app=express()
app.get('/',function(req,res){
res.header("Access-Control-Allow-Origin","*")
res.header("Access-Control-Allow-Headers","X-Requested-with")
res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS")
res.header("X-Powered-By","3.2.1")
res.header("Content-Type","application/json;charset=utf-8")
res.send({
say:"跨域成功"
})
})
app.listen(3001)
console.log('http://localhost:3001')
浏览器打印
跨域成功
使用JQuery封装的jsonp进行跨域
前端代码:
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script>
$(document).ready(function() {
$.ajax({
type: "GET",
url: "http://localhost:3001/",
dataType: "jsonp",
// jsonp:'callBack', // 后端获得回调函数名的参数,默认为callback ,如果更改,后端也要改为侦听callBack函数
// jsonpCallback:"_callBack", // 自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名
cache:false,
success: function(data) {
console.log(data)
},
error: function(e) {
console.log(e);
}
});
});
</script>
后端代码:
const express = require("express");
const app = express();
app.get("/", function(req, res) {
let _callBack = req.query.callback;
let responseData = {
say: "跨域成功"
};
if (_callBack) {
res.type('text/javascript')
res.send(_callBack + "(" + JSON.stringify(responseData) + ")")
} else {
res.send("没有跨域");
}
});
app.listen(3001);
console.log("http://localhost:3001");
使用websocket可以实现跨域(webcsocket的主要用于搭建即时通信)
前端代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>WebSocket</title>
</head>
<body>
<input id="sendText" type="text" />
<button id="sendBtn">发送</button>
<div id="recv"></div>
</body>
</html>
<script type="text/javascript">
var WebSocket = new WebSocket("ws://localhost:3001");
WebSocket.onopen = function() {
console.log("websocket open");
document.getElementById("recv").innerHTML = "Connected";
};
WebSocket.onclose = function() {
console.log("websocket close");
};
// 侦听消息更新
WebSocket.onmessage = function(e) {
document.getElementById("recv").innerHTML = e.data;
};
document.getElementById("sendBtn").onclick = function() {
var txt = document.getElementById("sendText").value;
WebSocket.send(txt);
};
</script>
后端代码:
const server=require('nodejs-websocket')
var app=server.createServer(function(connect){
console.log('新建一个链接')
connect.on('text',function(chunck){
console.log(`received:${chunck}`)
connect.sendText(chunck)
})
connect.on('close',function(code,reason){
console.log(`代码:${code}`)
console.log(`原因:${reason}`)
})
connect.on('error',function(err){
console.log(err)
})
})
app.listen(3001)
console.log('ws://localhost:3001')
后期更新服务器代理转发(vue-cli 可以在配置文件中使用proxy属性进行代理跨域)...