什么情况下会跨域
同源策略
同源策略是浏览器的行为,是为了保护本地数据不被JavaScript代码获取回来的数据污染,因此拦截的是客户端发出的请求回来的数据接收,即请求发送了,服务器响应了,但是无法被浏览器接收。
参数原因:
由 Netscape 公司 1995 年引入浏览器,它是浏览器最核心也最基本的安全功能,现在所有支持 JavaScript 的浏览器都会使用这个策略。如果缺少了同源策略,浏览器很容易受到 XSS、 CSFR 等攻击。
跨域
跨域就是非同源策略请求。
产生原因:请求方式、域名、端口 其中任意一个不同即为跨域:
URL | 说明 | 是否允许通信 |
---|---|---|
http://www.abc.com:80/index.html ==> http://www.abc.com:80/index.asp | 同协议 同域名 同端口 | 允许 |
http://www.abc.com:80/index.html ==> http://www.abc.com:8080/index.html | 同协议 同域名 不同端口 | 不允许 |
http://www.abc.com:80/index.html ==> https://www.abc.com:80/index.html | 不同协议 同域名 同端口 | 不允许 |
http://www.abc.com:80/index.html ==> http://www.acb.com:80/index.html | 同协议 不同域名 同端口 | 不允许 |
http://www.abc.com:80/index.html ==> https://www.acb.com:80/index.html | 不同协议 不同域名 同端口 | 不允许 |
http://www.abc.com:80/index.html ==> http://www.acb.com:8080/index.html | 同协议 不同域名 不同端口 | 不允许 |
http://www.abc.com:80/index.html ==> https://www.acb.com:8080/index.html | 不同协议 不同域名 不同端口 | 不允许 |
前端解决跨域
前端 需要在 vue.config.js
文件中通过 devServer
中的 proxy
来 配置代理 。
原理 :我们在 本地开发 的时候,通过 vueServe 起一个 本地的开发服务 ,这个 服务的地址 一般是 localhost , 端口 一般是 8080 ,如果我们在 本地起一个 node 服务 ,那么它的 端口 肯定是跟我们的 前端服务的端口 是不一样的,刚才在 上面表格中讲过 同一域名不同端口 也是 存在跨域问题 ,是 不在同一个域下 ,这个时候 调用接口 的话,受到 同源策略 影响,是 无法调取成功 的,我们可以用 proxy 来 设置代理 , 它会把我们所有的接口,代理到目标URL下 ,比如接口是 /api/getUserInfo
,我们 设置代理 是 http://localhost:4000
,这样的话请求的接口就会被代理到 http://localhost:4000
下,代理后请求接口时的URL : http://localhost:4000/#/api/getUserInfo
, 例子如下:
vue.config.js
const path = require('path') // 引入nodejs的path模块
const resolve = dir => path.join(__dirname, dir) // resolve方法用来加载路径
const BASE_URL = process.env.NODE_ENV === 'production' ? '/iview-admin/' : '/' // 判断当前为开发环境还是打包环境, '/'意思是代表指定在域名的根目录下,如果要指定到iview-admin下就这样写'/iview-admin/', production为生产坏境,development为开发环境
module.exports = {
lintOnSave: false, // 取消每次保存时都进行一次' ESLint '检测
publicPath: BASE_URL, // 项目的基本路径,vuecli2.0时打包经常静态文件找不到,就是需要配置这个属性为'./'
chainWebpack: config => { // 配置Webpack
config.resolve.alias
.set('@', resolve('src')) // 引入文件时候“ @ ”符号就代表src
.set('_c', resolve('src/components')) // 引入组件文件夹中的文件就可以用“ _c ”代替src/components
},
productionSourceMap: false, // 打包时不生成.map文件,会减少打包体积,同时加快打包速度
devServer: { // 跨域有2种解决方案: 1. 在后端的header中配置, 2. 使用devServer来配置代理解决跨域
proxy: 'http://localhost:4000' // 这里写需要代理的URL,这里会告诉开发服务器,将任何未知请求匹配不到静态文件的请求,都代理到这个URL来满足跨域
}
}
这里的代理的 URL地址 以及 端口号 一定要与服务端 一致 。
注意
前端配置代理 只是在 开发环境(develop) 好用,便于开发,在 生产环境(prod) 还是 需要由服务端解决跨域 。
这里需要注意,如果在 前端配置代理 ,需要在 src/config/index.js
(接下来的axios封装中用到了这个文件) 中添加一个 逻辑判断 如下:
src/config/index.js
// 如果当前是生产环境用生产环境地址,如果是开发环境并且在vue.config.js中配置了代理,
//就用空字符串【''】,如果未配置代理就用开发环境地址
export const baseURL= process.env.NODE_ENV === 'production' ? 'http://production.com' : 'http://develop.com'
后端解决跨域
如果不在 设置代理 ,可以在 后端设置header 来 解决跨域问题 ,这里 后端 用的是 nodejs ,在express
(nodejs的框架) 里使用 app.all 为 所有请求 都添加这 3 个 header 即可。
app.js
var createError = require('http-errors')
var express = require('express')
require('colors')
var path = require('path')
var cookieParser = require('cookie-parser')
var logger = require('morgan')
var indexRouter = require('./routes/index')
var usersRouter = require('./routes/users')
var app = express()
// view engine setup
app.set('views', path.join(__dirname, 'views'))
app.set('view engine', 'jade')
app.use(logger('dev'))
app.use(express.json())
app.use(express.urlencoded({ extended: false }))
app.use(cookieParser())
app.use(express.static(path.join(__dirname, 'public')))
app.all('*', function(req, res, next) { // 设置header
res.header('Access-Control-Allow-Origin', '*')
res.header('Access-Control-Allow-Headers', 'X-Requested-With,Content-Type')
res.header('Access-Control-Allow-Methods','PUT,POST,GET,DELETE,OPTIONS')
next()
})
app.use('/', indexRouter)
app.use('/users', usersRouter)
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404))
})
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message
res.locals.error = req.app.get('env') === 'development' ? err : {}
// render the error page
res.status(err.status || 500)
res.render('error')
})
module.exports = app