跨域定义
浏览器去请求学生列表页面时先从前端服务器获取该页面,此时页面中只有静态数据并没有学生列表数据,这时在浏览器的学生列表页面就自动调用获取学生列表数据的方法,所以请求是由浏览器发起的,而不是前端服务器获取所有学生列表数据后返回学生信息列表页面给浏览器。
由于获取数据的请求是浏览器发起的,而浏览器有同源策略,非同源的响应数据会被认为不安全进行拦截。
- 只要协议、主机、端口之一不同,就不同源,例如
- http://localhost:7070/a 和 https://localhost:7070/b 就不同源
- 同源检查是浏览器的行为,而且只针对 fetch、xhr(ajax)请求
- 如果是其它客户端,例如 java http client,postman,它们是不做同源检查的
- 通过表单提交、浏览器直接输入 url 地址这些方式发送的请求,也不会做同源检查
- 更多相关知识请参考
解决方法
一、请求响应头解决
- fetch 请求跨域,会携带一个 Origin 头,代表【发请求的资源源自何处】,目标通过它就能辨别是否发生跨域
- 我们的例子中:student.html 发送 fetch 请求,告诉 tomcat,我源自 localhost:7070
- 目标资源通过返回 Access-Control-Allow-Origin 头,告诉浏览器【允许哪些源使用此响应】
- 我们的例子中:tomcat 返回 fetch 响应,告诉浏览器,这个响应允许源自 localhost:7070 的资源使用,只需要在SpringBoot项目中增加@CrossOrigin即可,或者@CrossOrigin(“http://localhost:7070”)
二、代理解决
通过代理方式解决前端跨域问题,之前的页面获取学生列表数据需要浏览器向后端发起请求,现在所有请求都由前端服务器进行处理,由前端服务器向后端获取数据后再返回给浏览器,这样就不存在跨域问题。怎么区分请求需不需要进行代理转发给后端呢?可以通过请求路径进行判断,如果请求前缀为api
表示该请求需要进行代理转发给后端,如果不是则直接从前端服务器获取资源返回即可。
Java程序员所需Javascript知识一文查看如何搭建前端服务器
安装代理插件:
npm install http-proxy-middleware --save-dev
在 express 服务器启动代码中main.js
加入
import {createProxyMiddleware} from 'http-proxy-middleware'
//。。。
//表示请求路径前缀为/api时,使用代理模式向后端服务器进行转发
app.use('/api', createProxyMiddleware({ target: 'http://localhost:8080', changeOrigin: true }));
//直接返回前端服务器的静态资源
api.use(express.static('./'))
api.listen(7070)
fetch 代码改为
const resp = await fetch('http://localhost:7070/api/students')
或
const resp = await fetch('/api/students')