一、跨域是什么
跨域是指一个网页的客户端脚本(通常是 JavaScript)试图从不同的源(域名、协议或端口)访问资源时所遇到的限制。
例如,当一个网页(http://example.com
)中的 JavaScript 代码试图向另一个域名(http://another-example.com
)发送 HTTP 请求时,就会触发跨域限制。浏览器会阻止这种跨域请求,以确保用户数据的安全和防止恶意攻击。
二、为什么会有跨域限制
- 安全考虑:
- 防止恶意网站窃取用户数据。如果没有跨域限制,恶意网站可以通过发送跨域请求来获取用户在其他网站上的敏感信息,如登录凭证、个人资料等。
- 限制网页脚本的行为范围,确保脚本只能访问其来源网站的资源,减少潜在的安全风险。
- 同源策略:
- 浏览器遵循同源策略,即只有当两个页面的协议、域名和端口都相同时,才被认为是同源的。同源的页面之间可以自由地进行交互和访问资源,而不同源的页面之间则受到跨域限制。
三、解决跨域问题的方法
-
以下是对跨域问题各种解决方案的详细说明及代码示例
一、前端解决方案
- 使用代理服务器:说明:在开发环境中,像 Vue、React 等前端框架可以配置代理服务器。以 Vue CLI 创建的项目为例,在
vue.config.js
文件中配置代理,将特定路径的请求转发到后端服务器。这样前端发送请求时看似向同域的代理服务器发请求,代理再转发到后端,从而绕过浏览器跨域限制。 - JSONP(JSON with Padding):说明:JSONP 是利用
<script>
标签的跨域请求方法。通过动态创建<script>
标签,将请求的 URL 作为其src
属性的值,并把回调函数名作为 URL 的参数传递给后端。后端返回包含数据的 JavaScript 函数调用,前端的回调函数会自动执行从而获取数据。但 JSONP 只支持 GET 请求且存在安全风险,现在较少使用。代码示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
<script>
function jsonpCallback(data) {
console.log(data);
}
const script = document.createElement('script');
script.src = 'http://your-backend-url.com/data?callback=jsonpCallback';
document.body.appendChild(script);
</script>
</body>
</html>
二、后端解决方案
- 设置 CORS(Cross-Origin Resource Sharing):
- 说明:CORS 是 W3C 制定的标准机制,允许服务器声明哪些源可以访问其资源。在 Spring Boot 应用中,可以使用
@CrossOrigin
注解在控制器方法或类上设置跨域访问,或者通过实现WebMvcConfigurer
接口并覆盖addCorsMappings
方法进行全局跨域配置。 - 代码示例:
- 说明:CORS 是 W3C 制定的标准机制,允许服务器声明哪些源可以访问其资源。在 Spring Boot 应用中,可以使用
方法一:在控制器方法上使用 @CrossOrigin
注解:
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class MyController {
@CrossOrigin(origins = "http://your-frontend-url.com")
@GetMapping("/data")
public String getData() {
return "Some data";
}
}
方法二:实现 WebMvcConfigurer
接口进行全局配置:
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://your-frontend-url.com")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("*");
}
}
2.后端使用代理服务器(以 Nginx 为例):
说明:在后端也可以使用代理服务器来处理跨域请求。例如使用 Nginx 作为反向代理服务器,将来自不同源的请求转发到后端应用服务器,并设置适当的响应头来允许跨域访问。
server {
listen 80;
server_name your_domain.com;
location / {
proxy_pass http://your-backend-app.com;
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
}
}
三、其他解决方案
- 使用 WebSocket:
- 说明:WebSocket 是一种全双工通信协议,不受同源策略限制。前端可以通过建立 WebSocket 连接与后端进行实时通信,从而避免跨域问题。
- 代码示例:
- 服务器端:
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;
@ServerEndpoint("/websocket")
public class WebSocketServer {
private static final CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<>();
private Session session;
@OnOpen
public void onOpen(Session session) {
this.session = session;
webSocketSet.add(this);
}
@OnMessage
public void onMessage(String message) {
// 处理接收到的消息并发送回应
try {
session.getBasicRemote().sendText("Received: " + message);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void broadcast(String message) {
for (WebSocketServer webSocket : webSocketSet) {
try {
webSocket.session.getBasicRemote().sendText(message);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
2.客户端(HTML/JavaScript):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
<script>
const socket = new WebSocket('ws://your-backend-url.com/websocket');
socket.onmessage = function (event) {
console.log(event.data);
};
socket.send('Hello from client');
</script>
</body>
</html>
2.服务器端渲染(SSR)
- 说明:在服务器端渲染的应用中,前端代码在服务器上生成 HTML 页面,并将数据嵌入其中。这样浏览器在加载页面时,不需要发送跨域请求来获取数据,因为数据已经包含在页面中了。但服务器端渲染会增加服务器的负载和复杂性。
- 例如使用 Node.js 和一些 SSR 框架(如 Next.js 或 Nuxt.js),这些框架会在服务器端生成 HTML 页面并将数据嵌入其中,然后发送给客户端。这样可以避免客户端在加载页面时发送跨域请求来获取数据。但 SSR 会增加服务器的负载和复杂性,需要进行额外的配置和优化。