一、何为跨域
1、跨域究竟是什么
浏览器上的同源策略
2、跨域的特点:
- 跨域只存在于浏览器
- 不在浏览器发请求是不会存在跨域问题的
- http请求分为两大类: 普通
http
请求和ajax
请求(跨域是出现在ajax请求)
普通请求和ajax请求区别
最明显感官上的区别是:
普通请求会刷新页面,而ajax请求不会刷新页面
- 普通请求 一般只有
get
(a标签和地址栏输入回车)和post
(form表单) 页面会刷新 不会跨域
地址栏回车:
a标签:
本质是跳转网页,执行的操作相当于在浏览器地址栏中输入网址后回车
form表单:
form表单中有action
代表跳转路径,执行的操作相当于在浏览器地址栏中输入网址后回车
ajax
请求 一般get post delete put
(增删改查)一般都是异步发送的 页面不刷新 局部更新
跨域出现的地点
- 浏览器给服务器发
ajax
请求会跨域 因为跨域(同源策略)只存在于浏览器 - 服务器给服务器发
ajax
请求不会
什么条件产生跨域
- 同源(
协议 ip 端口
一致)不跨域 - 不同源就跨域(三个中间有一个不一样就跨域)
解决跨域可不光是后端的事儿
前端可以解决、后端解决。一般后端解决(cors
等)比前端解决容易
二、看看跨域长什么样儿
首先配置一台没有解决跨域的服务器
const express = require('express')
const app = express()
app.get('/hi', function (req, res) {
const result = {
status:200,
person:{
k:20,
gender:'男'
}
}
res.send(JSON.stringify(result))
})
app.listen(4000,()=>{
console.log('服务器启动成功','localhost:4000/hi')
})
用axios
向该服务器发送请求
<template>
<div>
<button @click="sendAjax">点击发送ajax请求</button>
<div>{{ajaxRtn}}</div>
</div>
</template>
<script>
import axios from 'axios'
export default {
name: 'App',
components: {
},
data() {
return {
ajaxRtn: ''
}
},
methods: {
sendAjax() {
let that = this
axios.get('http://localhost:4000/hi').then((res) => {
that.ajaxRtn = res.data
})
}
},
}
</script>
<style>
</style>
首先浏览器向http://localhost:8080/
发送请求获取页面数据(对应的动作是将webpack
打包完生成的地址在浏览器中打开)
获取页面数据下图示(此时还未发送ajax请求,并未产生跨域!)
dev-server
收到请求后会返回一个index.html
的包,得到页面:
页面点击按钮后向4000端口的服务器发送ajax请求,由于此时浏览器处于8080端口,向4000端口服务器发送请求必然会跨域。
点击按钮对应的回调函数:
sendAjax() {
let that = this
axios.get('http://localhost:4000/hi').then((res) => {
that.ajaxRtn = res.data
})
}
点击按钮对应的动作如下:
产生跨域,报错结果如下图:
三、配置代理服务器解决跨域
-
本身我们现在就跑在开发服务器
webpack-dev-server
(对应官网地址)
而这个服务器带了一个模块,这个模块可以支持我们使用代理
-
原理:
- 在浏览器发请求的时候,把这个请求发给服务器上的这个代理模块
- 再由这个代理模块转发给我们真正的服务器
- 这样的话,我们原来由浏览器直接发送请求到服务器就转化为服务器到服务器之间的请求
对应点击回调函数:
methods: {
sendAjax() {
let that = this
axios.get('http://localhost:8080/hi').then((res) => {
that.ajaxRtn = res.data
})
}
},
报错结果 (只是8080端口没有/hi下的数据才会返回404报错,并没有产生跨域):
- 你要让代理转发,那么得告诉代理你的这个请求什么情况需要转发
配置以固定什么开头的路径需要代理转发,代理看到这个路径是以它开头就会帮你转发
http-proxy-middleware
代理流程:
这个标识通常名为api
,所以http://localhost:8080/hi
加了标识变成了http://localhost:8080/api/hi
methods: {
sendAjax() {
let that = this
axios.get('http://localhost:8080/api/hi').then((res) => {
that.ajaxRtn = res.data
})
}
},
- 代理转发的时候会把路径交给真正的请求服务器,作为请求路径,需要把固定的开头去除
对应vue.config.js
中代码如下
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
lintOnSave: false,
devServer: {
proxy: {
'/api': {
target: 'http://localhost:4000',
pathRewrite: { '^/api': '' },
changeOrigin: true,
},
},
},
})