Skip to content

Commit d3e3fae

Browse files
author
zhaoshiwei1
committed
fix: correct minor grammatical errors and improve clarity in front-end cross-origin documentation
1 parent 27f2eec commit d3e3fae

File tree

1 file changed

+5
-131
lines changed

1 file changed

+5
-131
lines changed

docs/goodblog/frontend/network/深入理解前端跨域:从原理到全方位解决方案.md

Lines changed: 5 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# 万字长文带你理清楚前端跨域所有解决方案的细节
22

3-
前端时间chrome更新了204版本之后,由于新版的chrome把iframe 放在了独立的进程渲染,导致公司的的一个angular子应用使用iframe嵌套在主应用中发生了跨域,心想在解决问题的时候顺便把跨域相关的知识全部整理一遍吧
3+
> 前段时间chrome更新了204版本之后,由于新版的chrome把iframe 放在了独立的进程渲染,导致公司的的一个angular子应用使用iframe嵌套在主应用中发生了跨域,心想在解决问题的时候顺便把跨域相关的知识全部整理一遍吧
44
55
## 一、什么是跨域?
66

@@ -27,11 +27,11 @@ https://www.example.com:443/api/posts ✓ 同源(只是路径不同)
2727

2828
### 同源策略限制了什么?
2929

30-
在我的开发经验中,同源策略主要限制以下几个方面:
30+
同源策略主要限制以下几个方面:
3131

32-
1. **Ajax 请求**:不能向不同源的服务器发送请求
33-
2. **DOM 访问**:不能访问跨域 iframe 的 DOM
34-
3. **Cookie/LocalStorage/IndexDB**:不能读取跨域的存储数据
32+
1. **Ajax 请求**: 可以向不同源服务器发起请求,但浏览器会限制 JavaScript 代码读取非同源响应的内容(比如无法访问 response 数据)。也就是说,跨域的 Ajax 请求可以发出,但响应会被同源策略拦截,页面拿不到数据。这就是常见的“跨域请求被阻止”问题。
33+
2. **DOM 访问**: 不能访问跨域 iframe 的 DOM
34+
3. **Cookie/LocalStorage/IndexDB**: 不能读取跨域的存储数据
3535

3636
```mermaid
3737
graph TD
@@ -67,14 +67,6 @@ fetch("https://api.example.com/users", {
6767
.then((response) => response.json())
6868
.then((data) => console.log(data))
6969
.catch((error) => console.error("Error:", error));
70-
71-
// 或使用 axios
72-
axios
73-
.post("https://api.example.com/users", {
74-
name: "John",
75-
})
76-
.then((response) => console.log(response.data))
77-
.catch((error) => console.error("Error:", error));
7870
```
7971

8072
**后端代码**(Node.js + Express):
@@ -123,43 +115,6 @@ app.post("/users", (req, res) => {
123115
app.listen(3000);
124116
```
125117

126-
**使用 cors 中间件**(推荐):
127-
128-
```javascript
129-
const express = require("express");
130-
const cors = require("cors");
131-
const app = express();
132-
133-
// 简单配置
134-
app.use(cors());
135-
136-
// 详细配置
137-
app.use(
138-
cors({
139-
origin: ["https://www.mysite.com", "https://app.mysite.com"],
140-
methods: ["GET", "POST", "PUT", "DELETE"],
141-
allowedHeaders: ["Content-Type", "Authorization"],
142-
credentials: true, // 允许携带 Cookie
143-
maxAge: 86400, // 预检请求缓存 24 小时
144-
})
145-
);
146-
147-
// 或者动态配置
148-
app.use(
149-
cors({
150-
origin: function (origin, callback) {
151-
const whitelist = ["https://www.mysite.com", "https://app.mysite.com"];
152-
if (!origin || whitelist.includes(origin)) {
153-
callback(null, true);
154-
} else {
155-
callback(new Error("Not allowed by CORS"));
156-
}
157-
},
158-
credentials: true,
159-
})
160-
);
161-
```
162-
163118
#### CORS 的两种请求类型
164119

165120
在使用 CORS 时,我发现请求分为两种类型:
@@ -212,8 +167,6 @@ Access-Control-Request-Headers: Content-Type
212167

213168
### 方案二:JSONP ⭐⭐
214169

215-
JSONP 是我刚开始工作时常用的方案,现在已经很少用了,但了解它的原理还是很有帮助的。
216-
217170
#### 原理说明
218171

219172
JSONP 利用了 `<script>` 标签不受同源策略限制的特性。原理就是:
@@ -250,85 +203,6 @@ function jsonp(url, callbackName, callback) {
250203
jsonp("https://api.example.com/users", "handleUserData", function (data) {
251204
console.log("收到数据:", data);
252205
});
253-
254-
// 更完善的 JSONP 实现(支持 Promise)
255-
function jsonpPromise(url, params = {}) {
256-
return new Promise((resolve, reject) => {
257-
// 生成唯一的回调函数名
258-
const callbackName = `jsonp_${Date.now()}_${Math.random().toString(36).substr(2)}`;
259-
260-
// 定义全局回调函数
261-
window[callbackName] = function (data) {
262-
resolve(data);
263-
cleanup();
264-
};
265-
266-
// 创建 script 标签
267-
const script = document.createElement("script");
268-
269-
// 拼接 URL 参数
270-
const queryString = Object.keys(params)
271-
.map((key) => `${key}=${encodeURIComponent(params[key])}`)
272-
.join("&");
273-
274-
script.src = `${url}?callback=${callbackName}${queryString ? "&" + queryString : ""}`;
275-
276-
// 错误处理
277-
script.onerror = function () {
278-
reject(new Error("JSONP request failed"));
279-
cleanup();
280-
};
281-
282-
// 超时处理
283-
const timeout = setTimeout(() => {
284-
reject(new Error("JSONP request timeout"));
285-
cleanup();
286-
}, 10000);
287-
288-
function cleanup() {
289-
clearTimeout(timeout);
290-
if (script.parentNode) {
291-
document.body.removeChild(script);
292-
}
293-
delete window[callbackName];
294-
}
295-
296-
document.body.appendChild(script);
297-
});
298-
}
299-
300-
// 使用 Promise 版本
301-
jsonpPromise("https://api.example.com/users", { page: 1, limit: 10 })
302-
.then((data) => console.log("用户列表:", data))
303-
.catch((error) => console.error("请求失败:", error));
304-
```
305-
306-
**后端代码**(Node.js):
307-
308-
```javascript
309-
const express = require("express");
310-
const app = express();
311-
312-
app.get("/users", (req, res) => {
313-
const callbackName = req.query.callback;
314-
315-
if (!callbackName) {
316-
return res.status(400).json({ error: "Missing callback parameter" });
317-
}
318-
319-
const data = {
320-
users: [
321-
{ id: 1, name: "John" },
322-
{ id: 2, name: "Jane" },
323-
],
324-
};
325-
326-
// 返回 JavaScript 代码,调用回调函数
327-
res.type("application/javascript");
328-
res.send(`${callbackName}(${JSON.stringify(data)})`);
329-
});
330-
331-
app.listen(3000);
332206
```
333207

334208
#### 优劣势分析

0 commit comments

Comments
 (0)