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

摘要

在现代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. 总结(上篇)

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

相关推荐
山楂树の1 小时前
图像标注大坑:img图片 + Canvas 叠加标注,同步放大后标注位置偏移、对不齐?详解修复方案及亚像素处理原理
前端·css·学习·canva可画
本山德彪1 小时前
我做了一个拼豆图纸生成器,把照片秒变图纸
前端
DTrader1 小时前
用TS无法实盘量化? - 实盘均线策略
前端·api
进击的夸父1 小时前
vfojs:Vue 超集架构,外壳React灵魂Vue
前端
编程老船长1 小时前
解决不同项目需要不同 Node.js 版本的问题
前端·vue.js
Wect1 小时前
LeetCode 5. 最长回文子串:DP + 中心扩展
前端·算法·typescript
漫游的渔夫1 小时前
前端开发者做 Agent:别写成一次请求,用 5 步受控循环防止 AI 乱跑
前端·人工智能·typescript
kyriewen3 小时前
Webpack vs Vite:一个是“老黄牛”,一个是“猎豹”,你选谁?
前端·webpack·vite
打小就很皮...3 小时前
html2canvas + jsPDF 生成 PDF 的踩坑与解决方案总结
前端·pdf
全栈前端老曹3 小时前
【前端地图】多地图平台适配方案——高德、百度、腾讯、Google Maps SDK 差异对比、封装统一地图接口
前端·javascript·百度·dubbo·wgs84·gcj-02·bd09