什么是跨域问题

跨域问题是指在浏览器上运行的Web应用程序试图经过XMLHttpRequest或Fetch API等办法向不同源(域名、协议或端口)的服务器发送恳求时,浏览器会依据同源战略阻挠这种行为。同源战略是一种安全机制,用于约束来自不同源的页面对当前页面的拜访。它能够避免歹意的网站经过跨域恳求获取用户的个人信息或进行未授权操作。

同源战略要求恳求的协议、域名和端口号有必要完全相同才被认为是同源。也就是说只要协议、域名和端口号,任何一项与当前页面的协议、域名、端口号不一致,就会被浏览器阻挠。在这种状况下,浏览器会抛出一个跨域过错,导致恳求失利。

跨域是浏览器行为。实际上我们宣布的恳求现已抵达服务器了,但是服务器回来数据时被浏览器约束了

如何处理

一、JSONP:利用 script 标签的跨域特性,经过动态创建 script 标签并设置其 src 特点为跨域的 URL,服务器端回来的呼应数据需求用特定的格局包裹起来,并经过回调函数回来给客户端。

客户端代码:

function handleResponse(response) {
  //处理服务器回来的数据
}
var script = document.createElement('script');
script.src = 'https://jsonp.com/data?callback=handleResponse';
document.body.appendChild(script);

服务端代码:

var data = { name: 'John', age: 30 };
var jsonpResponse = 'handleResponse(' + JSON.stringify(data) + ');';
res.send(jsonpResponse);

关于JSONP的补充

  • JSONP只支撑GET恳求,不支撑POST等其他HTTP办法。
  • 由于JSONP恳求是经过动态创建script标签完成的,所以需求确保被恳求的数据源回来的是JSONP格局的数据,而不是一般的JSON格局,否则在处理时会呈现语法过错。
  • 由于JSONP恳求是经过script标签完成的,所以无法在恳求时设置恳求头(例如Content-Type),也无法获取呼应头(例如Cookie),这是JSONP与XHR等其他跨域恳求办法的一个差异。

二、CORS(跨域资源共享):在服务器端设置相应的呼应头,答应跨域恳求。通常在服务器端设置 Access-Control-Allow-Origin 头部,指定答应的来源域名,即可完成跨域恳求的许可。CORS 支撑各种 HTTP 恳求办法,而且更加灵活和安全。

客户端代码:

fetch('http://CORS.com/api/data', {
  method: 'GET',
  headers: {
    'Content-Type': 'application/json',
  },
  mode: 'cors',
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error))

服务端代码:

const express = require('express');
const app = express();
app.use((req, res, next) => {
  res.setHeader('Access-Control-Allow-Origin', '*');
  res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
  res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
  next();
});
app.get('/api/data', (req, res) => {
  const data = { message: 'Hello, World!' };
  res.json(data);
});
app.listen(3000, () => {
  console.log('Server listening on port 3000');
});

优点:

  • 安全性高:CORS 是一种安全的跨域拜访处理方案,经过约束答应跨域拜访的源和办法,能够有效地避免歹意进犯。
  • 灵活性强:CORS 支撑不同类型的恳求,包含 GET、POST、PUT、DELETE 等,一起也支撑不同类型的数据传输格局,比方 JSON、XML 等。
  • 运用方便:CORS 只需求在服务器端设置呼应头,就能够完成跨域拜访,运用方便。

不足:

  • 兼容性问题:CORS 在某些旧版的浏览器中不支撑,需求进行特殊处理。
  • 跨域恳求的额定消耗:在运用 CORS 处理跨域恳求时,需求发送预检恳求,这会增加恳求的时间和带宽消耗。
  • CSRF 进犯:虽然 CORS 是一种安全的跨域拜访处理方案,但仍然或许存在 CSRF(Cross-Site Request Forgery)进犯,需求在运用时加以留意。能够运用 Cookie、Token 或者恳求头中的特定信息来验证恳求是否合法。

三、代理服务器:在同源战略约束下,能够经过在同域名下的服务器上设置一个代理服务器,将客户端恳求转发到方针服务器,再将相应的成果回来给客户端。客户端只需求与代理服务器通讯,而不是直接与方针服务器通讯,直接完成了跨域恳求。

案例一:

1、需求:运用axios接纳server1.js的服务

2、完成:

App.vue

<template>
	<div>
		<button @click="getStudents">获取学生信息</button>
	</div>
</template>
<script>
        import axios from 'axios'
	export default {
		name:'App',
		methods:{
			getStudents(){
				//留意:敞开代理服务器后,get中的端口号要改为前端所在的端口号,即8080
				axios.get('http://localhost:8080/students').then(
					response => {
						console.log('恳求成功了',response.data)
					},
					error => {
						console.log('恳求失利了',error.message)
					}
				)
			},
		},
	}
</script>

vue.config.js(这里要先封闭vue,写完后在重启,否则配置更改不会生效)

const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
  transpileDependencies: true,
  // 封闭语法检查
  lintOnSave: false,
  // 敞开代理服务器,留意:这里的端口号写后端的端口号(办法一)
  devServer: {
    proxy: 'http://localhost:5000'
  },
})

案例二:

1、需求:运用axios接纳server1.js和server2.js的服务

2、完成:

  • App.vue
<template>
	<div>
		<button @click="getStudents">获取学生信息</button>
		<button @click="getCars">获取汽车信息</button>
	</div>
</template>
<script>
        import axios from 'axios'
	export default {
		name:'App',
		methods:{
			getStudents(){
				//留意:采用了写法二,要加上前缀 /atguigu
				axios.get('http://localhost:8080/atguigu/students').then(
					response => {
						console.log('恳求成功了',response.data)
					},
					error => {
						console.log('恳求失利了',error.message)
					}
				)
			},
			getCars(){
				//留意:采用了写法二,要加上前缀 /demo
				axios.get('http://localhost:8080/demo/cars').then(
					response => {
						console.log('恳求成功了',response.data)
					},
					error => {
						console.log('恳求失利了',error.message)
					}
				)
			},
		},
	}
</script>
  • vue.config.js
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
  transpileDependencies: true,
  // 封闭语法检查
  lintOnSave: false,
  // 敞开代理服务器,留意:这里的端口号写后端的端口号(办法一)
  // devServer: {
  //   proxy: 'http://localhost:5000'
  // },
  // 敞开代理服务器(办法二)
  devServer: {
    proxy: {
      // /atguigu 是恳求的前缀
      '/atguigu': {
        target: 'http://localhost:5000',
        //重写途径,把一切途径中包含/atguigu的途径替换为空字符串
        pathRewrite: {'^/atguigu':''}, 
        // 用于支撑websocket
        ws: true,
        // 用于操控恳求头中的host值
        changeOrigin: true
      },
      '/demo': {
        target: 'http://localhost:5001',
        //重写途径,把一切途径中包含/atguigu的途径替换为空字符串
        pathRewrite: {'^/demo':''}, 
        // 用于支撑websocket
        ws: true,
        // 用于操控恳求头中的host值
        changeOrigin: true
      },
    }
  }
})

四、WebSocket:WebSocket 是一种根据 TCP 协议的全双工的通讯协议,它不受同源战略的约束,在树立连接后,客户端与服务器之间能够直接进行双向通讯。因此,能够利用 WebSocket 完成跨域通讯。

总结
跨域问题是在Web开发中常遇到的挑战之一。当页面上的JavaScript代码测验经过XMLHttpRequest或Fetch API等办法向不同域名、协议或端口的服务器发送恳求时,浏览器会依据同源战略(Same-Origin Policy)阻挠这种行为。处理跨域问题有多种办法,常用的包含JSONP、CORS、代理服务器等。

选择不同的处理方案取决于项目需求和后端服务的支撑状况。经过正确的处理方案,能够确保数据通讯的安全性和稳定性,进步开发功率和用户体会。跨域问题是web开发中不行忽视的问题,了解处理方案关于前端开发者至关重要。