在我们使用ajax进行前后端数据交互的时候,经常会遇到一个跨域的报错信息,为什么会产生报错信息?
因为产生跨域
这是因为浏览器的同源策略。这是浏览器最核心也最基本的安全功能,它阻止一个域上加载的脚本去获取或操作另一个域上的文档属性。(也就是说,受到请求的URL的域必须与当前web页面的域相同),如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。
哪些情况会产生跨域?
端口不同
协议不同
域名不同
相同的网址和域名对应的IP不同 //localhost和127.0.0.1会生跨域
总结:端口不同,域名不同,协议不同都会出现跨域
同源策略限制以下几种行为:
Cookie、LocalStorage 和 IndexDB 无法读取
DOM和JS对象无法获得
AJAX 请求不能发送
如何解决解决跨域?
在前端开发中,不可避免要出现跨域问题,下面提供四种方法供参考。
注意:一般出现跨域应该是前后端共同配置解决
方法一:服务器代理
基本原理:服务器之间的请求没有跨域问题。
首先前端请求自己的服务器。 通过第三方中间件cors,来解决前端和自己的服务器之间的跨域问题。
我方服务器发起对目标服务器发送服务器请求。
将网路请求的结果返回给前端
前端代码:
let url ='http://localhost:3000/cors';//请求自己的服务器
$.get(url,(data)=>{
console.log(data);//后端返回的数据
})
server.js:
const cors = require('cors')
const axios =require('axios')
const express = require('express')
const path = require('path')
const app = express()
// 通过第三方中间件cors 来实现跨域问题
app.use(cors())//如果访问的是目标服务器,那么这里就相当于一个服务器代理
app.get('/cors',(req,res)=>{
console.log('请求到了')
let url ='http://ustbhuangyi.com/music/api/getDiscList?g_tk=1928093487&inCharset=utf-8&outCharset=utf-8¬ice=0&format=json&platform=yqq&hostUin=0&sin=0&ein=29&sortId=5&needNewCode=0&categoryId=10000000&rnd=0.2209329929181545'
// 直接发起一个服务器请求
axios.get(url)
.then((data)=>{
// console.log(data.data)
res.send(data.data)
})
})
app.listen(3000,()=>{
console.log('服务器启动')
})
方法二:JSONP方式(前端常用)
核心:script标签的src属性不存在跨域,可以加载任何文件信息。
一般第三方接口可以使用此方法,也是服务器和客户端之间通信的常用方法。全平台浏览器都支持。
比如,需要返回一个淘宝推荐的数据接口
let url = https://suggest.taobao.com
/sug?code=utf-8&q=%E8%A1%A3%E6%9C%8D&_ksTS=1577354356112_350
&callback=taobao&k=1&area=c2c&bucketid=3//前端页面在调用接口时,需要以callback=回调函数名的形式
可以通过script标签实现跨域请求,然后再用json数据并执行回调函数
<script>
function taobao(data){
console.log(data);
}
</script>
这个接口打印出来的数据如下图所示
若项目使用vue写的,那么也可以用jsonp这个模块
api.js
import jsonp from 'jsonp'
const getData = () => {
let url = 'https://suggest.taobao.com/sug?code=utf-8&q=%E8%A1%A3%E6%9C%8D&_ksTS=1577354356112_350'
// param给后端传递函数名的字段 由后端确定的 不能随便写
return new Promise((resolve, reject) => {
jsonp(url,{param:'callback'},(err, data) => {
if(err){
reject(err)
}else {
resolve(data)
}
})
})
}
index.vue
import { getData} from "api/api.js";
getData().then((res)=>{
console.log(res) // 若是请求成功,得到数据
})
这个方法很简单但也有弊端:
jsonp请求方式只能是get。使数据在传递的过程中毫无安全性可言,而且所能传输的数据长度也相当有限。
接口必须符合jsonp格式,否则采用此方法没意义。
方法三:cors设置请求的相应头字段
CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
支持所有类型的HTTP请求,但浏览器IE10以下不支持),适合做ajax各种跨域请求。
后端代码:
var express = require('express');
var app = express();
// 中间件 解决跨域问题
function middleware(req, res, next) {
console.log('这里是中间件')
// 跨域处理
res.header("Access-Control-Allow-Origin", "*");//设置允许跨域的域名,*代表允许任意域名跨域
res.header("Access-Control-Allow-Headers", "X-Requested-With");//允许的header类型
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");
next(); // 执行下一个路由
}
//all是路由中指代所有的请求方式
app.all(middleware) //使用全局自定义中间件,放到起始位置
app.get('/test', function (req, res) {
res.send(req.query);
})
app.listen(3000, function () {
console.log('服务器启动');
})