跨域
跨域是我们前端开发中经常会遇到的问题,那么跨域到底是什么,我们怎么去解决他们呢
问题演示
把前端代码单独运行就会报错了
跨域问题分析
原因:发起ajax请求的页面的地址和ajax接口地址不在同一个域中
跨域报错:不同源的ajax请求会导致报跨域的错误
同源:浏览器端和服务器端的协议、域名、端口号完全一样就是同源,只要有一个不一样就是跨域
跨域问题出现的根本原因:浏览器的同源策略,同源策略是一个重要的安全策略,它限制一个origin的文档或者它加载的脚本如何能与另一个源的资源进行交互。
注意:错误是发送在浏览器端,请求是可以正常从浏览器端发送到服务器端,服务器也可以处理请求,只是返回到浏览器端的时候出错了
解决办法
- 让浏览器端和服务器端的三要素相同,处于同源
- 设置服务器代理
- 请求是ajax,改发JSONP
- CORS
- 通过在被请求的路由中设置header头,可以实现跨域
res.setHeader('Access-Control-Allow-Origin', '*')
手动实现解决跨域问题
通过在被请求的路由中设置header头,可以实现跨域
app.get('/get', (req, res) => {
// * 表示允许任何域名来访问
res.setHeader('Access-Control-Allow-Origin', '*')
// 允许指定源访问
// res.setHeader('Access-Control-Allow-Origin', 'http://www.xxx.com')
res.send(Date.now().toString())
})
注意:
- 这种方案无需客户端作出任何变化(客户端不用改代码),就当跨域问题不存在一样。
- 服务端响应的时候添加一个
Access-Control-Allow-Origin的响应头
CORS解决跨域问题
- CORS是一个W3C标准,它允许浏览器向跨源服务器,发出
XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制 - CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10(ie8通过XDomainRequest能支持CORS)
- cors是一个npm包,需要单独下载使用
- 当做express中的中间件,注意代码应该放在顶部
const cors = require('cors')
app.use(cors())
这样做的好处是不用每个接口内部写res.setHeader
JSONP解决跨域问题
原理:
- script的src属性可以请求外部的js文件,这个请求不是ajax,它没有跨域问题
- 借助script的scr属性请求服务器上的接口
- 服务器的接口返回javascript脚本,并附上要返回的
js数据代码,返回的数据必须加双引号(字符串类型)
JSONP的基本实现
在实际的开发中,前端使用jquery,后端使用nodejs+express
jquery中的ajax已经封装好了的jsonp方式,可以直接使用
改造一个接口,返回一个函数调用表达式
后端代码
const express = require('express');
const app = express();
app.get('/get', (req, res) => {
const data = JSON.stringify({a:1,b:2})
const fnStr = `fn(${data})`
res.send(fnStr); // 返回字符串,内容是:函数调用语句
})
app.listen(3000, () => {
console.log('你可以通过http://localhost:3000来访问...');
});
前端代码
<script>
function fn(rs) {
console.log(rs);
}
</script>
<html>
<script src="http://localhost:3000/get"></script>
</html>
JSONP的实操
前端代码
<!-- 引入jquery -->
<script src="./js/jquery-1.12.2.js"></script>
<script>
//调用jquery里面的方法
$.ajax({
type: 'GET',
url: 'http://localhost:3000/getJSONP',
success: function (result) {
console.log(result);
},
dataType: 'jsonp' // 必须要指定dataType为jsonp
});
</script>
后端代码
// 静态资源托管,直接访问public.JSONP.html
//1. 导入包
const express = require('express')
//2. 调用
const app = express()
//3.静态资源托管
app.use(express.static('public'))
//4.jsonp
app.get('/getJSONP', (req, res) => {
const data = { name: '薛之谦', music: ['怪咖', '笑场', '迟迟'] }
res.jsonp(data)
})
//5.端口号监听,启动服务
app.listen(3000, () => {
console.log('服务器已启动')
})
注意:原来是res.json,要改成res.jsonp
CORS和JSONP的区别
JSONP:
- 不是ajax
- 只能支持get方式
- 兼容性比较好
CORS: - 前端不需要做额任何的修改
- 是ajax
- 支持各种方式的请求
- 浏览器的支持不太好