本文已参与「新人创作礼」活动,一起开启掘金创作之路。
什么是跨域?
跨域,是指浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对JavaScript实施的安全限制。
同源策略限制以下行为:
- Cookie、LocalStorage 和 IndexDB 无法读取
- DOM 和 JS 对象无法获取
- Ajax请求发送不出去
解决跨域的方法(3种)
- JSONP
- 后端解决( CROS)
- 前端解决(前后端--Vue等)
- JSONP
- 普通请求值 XHR,希望得到服务端返回的 content-type 一般是 json
- JSONP 发出的是 script 请求,希望得到的返回是 js 脚本
JSONP原理:
发送 ajax 请求的时候,设置dataType:"jsonp",将使用 JSONP 方式调``用函数,
函数的 url 变为myurl?callback=e5bbttt的形式,
根据一个临时方法名,后端会根据callback的值返回一个 js 脚本
JSONP弊端:
1. 需要服务器改动代码
2. 只支持 GET 请求
3. 发送的不是 xhr 请求
4. 不安全
- CROS(用于后端解决跨域问题)
SpringWebConfiguration.java
@Configuration
@EnableWebMvc
public class SpringWebConfiguration implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")// 添加映射路径
.allowedHeaders("*")// 放行哪些原始请求头部信息
.exposedHeaders("*")// 暴露哪些头部信息
.allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE", "TRACE", "HEAD", "PATCH")// 放行哪些请求方式
.allowCredentials(true)// 是否发送 Cookie
.maxAge(3600)// 最大时间
.exposedHeaders("Authorization")
.allowedOriginPatterns("*");
// 指定明确地址
// .allowedOriginPatterns("http://127.0.0.1:8080")
// .allowedOriginPatterns("http://127.0.0.1:8082");
}
}
如说使用发的是前后端开发(例如VUE等),为了方便开发不用每次写全域名还需要在axios中作如下配置
request.ts
import axios, {AxiosRequestConfig, AxiosResponse} from 'axios'
import {ElMessage, ElNotification} from 'element-plus'
import {useRouter} from 'vue-router'
import * as nProgress from 'nprogress'
import {useMainStore} from '../store'
const router = useRouter()
axios.create({
baseURL: 'http://127.0.0.1:8080',
timeout: 5000,
withCredentials: true
})
axios.defaults.headers.post['Content-Type'] = 'application/json;charset=utf-8';
axios.interceptors.request.use(async (config: AxiosRequestConfig) => {
nProgress.start()
if (useMainStore().getAuthorization && localStorage.getItem('Authorization')) {
if (config.headers) {
config.headers.Authorization = useMainStore().getAuthorization
}
}
return config;
}, ((error: any) => {
ElNotification.error('请求错误!')
return Promise.reject(error);
}))
axios.interceptors.response.use(async (response: AxiosResponse) => {
nProgress.done()
switch (response.status as number) {
case 200 || 201:
return response;
case 401:
ElMessage.warning('您未登录')
await router.push('/login')
break
case 403:
ElMessage.warning('无权访问')
break
case 500:
ElMessage.error('服务器异常')
break
default:
ElNotification.error('未知异常')
}
}, ((error: any) => {
ElNotification.error('响应错误!')
return Promise.reject(error);
}
))
export default axios
- Proxy(前端代理方式)
- 使用vue时:
vue.config.js
module.exports = {
lintOnSave: false,
devServer: {
// 前端地址
host: '127.0.0.1',
// 前端端口
port: 3000,
// 设置代理
proxy: {
'/api': {
//远程服务器地址
target: 'http://127.0.0.1:8080',
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
}
}
}
}
- 使用vite时:
vite.config.ts
import {defineConfig} from 'vite'
import vue from '@vitejs/plugin-vue'
import * as path from 'path'
export default defineConfig({
plugins: [
vue()
],
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'),
'@views': path.resolve(__dirname, 'src/views'),
'@layout': path.resolve(__dirname, 'src/layout'),
'@components': path.resolve(__dirname, 'src/components')
}
},
server: {
host: '127.0.0.1',
port: 3000,
cors: true,
open: false,
proxy: {
'/api': {
target: 'http://127.0.0.1:8080',
changeOrigin: true,
rewrite: (path: string) => path.replace(/^/api/, '')
}
}
}
})
test.vue
<template>
<el-button type="success" @click="testProxy">测试</el-button>
</template>
<script lang="ts" setup>
import axios from './utils/request'
const testProxy = async () => {
const { data } = await axios({
method: 'GET',
url: '/api/test'
})
switch( data.code as number ){
case 200 || 201:
ElMessage.warning('请求成功')
break
case 500:
ElMessage.warning('服务器异常')
break
default:
ElMessage.warning('未知异常')
}
}
</script>
<style scoped lang="scss">
</style>