深入理解跨域:同源策略、问题本质与解决方案(上)

摘要

在现代Web开发中,前端与后端分离的架构已成为主流。前端应用通常部署在独立的域名或端口,通过API请求与后端服务进行数据交互。然而,这种分离也带来了前端开发者绕不开的"跨域问题"。跨域,即Cross-Origin,是浏览器基于安全考虑实施的"同源策略"所导致的限制。本文将作为系列文章的上篇,深入剖析同源策略的定义、目的与限制,揭示跨域问题的本质,并为读者建立对跨域问题的底层认知,为后续理解各种解决方案打下坚实基础。

1. 什么是"源"(Origin)?

在Web安全领域,理解"源"的概念是理解同源策略的前提。一个"源"由以下三个部分组成:

  • 协议(Protocol) :例如http://https://
  • 域名(Domain) :例如www.example.comapi.example.com
  • 端口(Port) :例如80(HTTP默认端口)、443(HTTPS默认端口)、8080

只有当这三个部分都完全相同时,两个URL才被认为是"同源"的。任何一个部分不同,都被认为是"异源"(Cross-Origin)。

示例

假设当前页面URL为 http://www.example.com:80/index.html

URL 是否同源? 原因
http://www.example.com:80/data 协议、域名、端口都相同
https://www.example.com:80/data 协议不同(http vs https)
http://api.example.com:80/data 域名不同(www.example.com vs api.example.com
http://www.example.com:8080/data 端口不同(80 vs 8080)

2. 同源策略(Same-Origin Policy):Web安全的基石

2.1 定义与目的

同源策略 (Same-Origin Policy)是浏览器最核心、最基本的安全功能。它限制了一个源的文档或脚本如何与另一个源的资源进行交互。简而言之,就是一个源的Web页面只能访问同源的资源,不能直接访问异源的资源

同源策略的主要目的是为了保护用户的信息安全,防止恶意网站窃取或篡改用户数据。试想一下,如果没有同源策略,当你登录了银行网站后,同时又打开了一个恶意网站。这个恶意网站就可以通过JavaScript向银行网站发送请求,获取你的账户信息,甚至进行转账操作,这将带来巨大的安全风险。

2.2 同源策略的限制

同源策略主要限制了以下三种跨域行为:

  1. XMLHttpRequest 和 Fetch API 请求:这是最常见的跨域问题。浏览器会阻止从一个源发起的XMLHttpRequest或Fetch请求,去获取另一个源的资源。即使请求成功返回了数据,浏览器也会阻止JavaScript访问这些数据。
  2. DOM操作 :不同源的iframe之间不能互相访问DOM内容。例如,父页面无法获取iframe内部的DOM元素,iframe也无法访问父页面的DOM。
  3. Cookie、LocalStorage 和 IndexedDB:不同源的页面之间无法互相读取或修改对方的Cookie、LocalStorage和IndexedDB等客户端存储数据。

需要注意的是 :同源策略只是一种浏览器行为 。服务器之间进行数据交互时,并没有同源策略的限制。例如,后端服务器可以向任何其他服务器发送请求并获取数据。跨域问题只存在于浏览器端,是为了保护用户在浏览网页时的安全。

3. 跨域问题的本质

跨域问题的本质是浏览器对JavaScript发起的HTTP请求的一种安全限制。当浏览器检测到JavaScript代码尝试访问一个与当前页面不同源的资源时,它会阻止该请求的响应数据被JavaScript访问,从而避免潜在的安全风险。

一个典型的跨域场景

假设你的前端应用部署在 http://localhost:3000,而后端API服务运行在 http://localhost:8080。当前端页面中的JavaScript代码尝试通过XMLHttpRequestfetchhttp://localhost:8080/api/data 发送请求时,由于协议、域名和端口中至少有一个不同(端口不同:3000 vs 8080),浏览器就会触发同源策略,阻止前端JavaScript获取到后端返回的数据,即使后端服务器已经成功响应了请求。

从提供的文件看跨域场景

server.js文件中,我们看到了一个简单的Node.js HTTP服务器,它监听在8080端口,并提供了一个/api/hello接口:

javascript 复制代码
// server.js
const http = require('http');
​
const server = http.createServer((req, res) => {
    if(req.url ==='/api/hello'&&req.method ==='GET'){
        console.log('/////');
        res.writeHead(200,{
            'Content-Type':'text/javascript'
        });
        const data = {
            code:0,
            msg:'字节,我来了'
        }
        // json with padding 
        res.end("callback("+ JSON.stringify(data) +")")
    }else{
        res.writeHead(404,{
            'Content-Type':'text/plain'
        });
        res.end('Not Found');
    }
})
​
server.listen(8080,()=>{
    console.log(`Server is running on port 8080`);
})

这个server.js返回的Content-Typetext/javascript,并且响应内容是callback(...)的形式,这暗示了它可能被设计用于JSONP 这种跨域解决方案。如果前端页面(例如部署在http://localhost:3000index.html)尝试通过script标签加载这个http://localhost:8080/api/hello接口,就会涉及到跨域。

index.html本身是一个本地文件,或者部署在某个前端服务器上。如果index.html中的JavaScript尝试直接通过XMLHttpRequestfetch请求http://localhost:8080/api/hello,那么就会遇到典型的跨域问题。

4. 总结(上篇)

通过上篇的探讨,我们明确了"源"的定义,理解了同源策略作为浏览器安全基石的重要性,以及它对跨域请求的限制。我们还通过实际案例揭示了跨域问题的本质,即浏览器出于安全考虑对异源请求的响应数据进行拦截。在下一篇中,我们将深入探讨各种解决跨域问题的方案,包括它们的原理、优缺点以及适用场景,帮助读者在实际开发中选择最合适的跨域解决方案。

相关推荐
卑微前端在线挨打4 分钟前
2025数字马力一面面经(社)
前端
OpenTiny社区19 分钟前
一文解读“Performance面板”前端性能优化工具基础用法!
前端·性能优化·opentiny
拾光拾趣录40 分钟前
🔥FormData+Ajax组合拳,居然现在还用这种原始方式?💥
前端·面试
不会笑的卡哇伊1 小时前
新手必看!帮你踩坑h5的微信生态~
前端·javascript
bysking1 小时前
【28 - 记住上一个页面tab】实现一个记住用户上次点击的tab,上次搜索过的数据 bysking
前端·javascript
Dream耀1 小时前
跨域问题解析:从同源策略到JSONP与CORS
前端·javascript
前端布鲁伊1 小时前
【前端高频面试题】面试官: localhost 和 127.0.0.1有什么区别
前端
HANK1 小时前
Electron + Vue3 桌面应用开发实战指南
前端·vue.js
極光未晚1 小时前
Vue 前端高效分包指南:从 “卡成 PPT” 到 “丝滑如德芙” 的蜕变
前端·vue.js·性能优化
郝亚军1 小时前
炫酷圆形按钮调色器
前端·javascript·css