js基础
Ajax原理
AJAX(Asynchronous JavaScript and XML)是一种在网页中异步加载数据的技术,它允许在不重新加载整个页面的情况下更新页面的一部分。以下是 AJAX 的基本原理及其工作流程:
基本概念
- 异步通信:AJAX 允许浏览器在后台与服务器进行通信,而不影响当前页面的显示。
- XMLHttpRequest 对象:这是 AJAX 核心的对象,用于与服务器进行通信。
- JSON 数据:虽然名为 XML,但实际上现代 AJAX 更常使用 JSON 格式来传输数据,因为它更轻便且更容易解析。
工作流程
- 初始化 XMLHttpRequest 对象:创建一个新的 XMLHttpRequest 对象实例。
- 设置回调函数:指定一个回调函数来处理服务器响应。
- 打开连接 :调用
open()
方法指定请求类型(GET 或 POST)、URL 和是否异步。 - 发送请求 :调用
send()
方法发送请求到服务器。 - 接收响应:在回调函数中处理服务器返回的数据。
示例代码
HTML 结构
xml
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>AJAX Example</title>
</head>
<body>
<button id="loadData">Load Data</button>
<div id="result"></div>
<script src="ajax.js"></script>
</body>
</html>
JavaScript (ajax.js)
javascript
JavaScript
document.getElementById('loadData').addEventListener('click', function() {
// 创建 XMLHttpRequest 对象
var xhr = new XMLHttpRequest();
// 设置回调函数
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
// 请求成功,处理响应数据
document.getElementById('result').innerHTML = xhr.responseText;
}
};
// 打开连接
xhr.open('GET', 'data.json', true);
// 发送请求
xhr.send();
});
服务器端数据 (data.json)
javascript
JSON
{
"message": "Hello, this is data loaded via AJAX!"
}
详细步骤解释
-
创建 XMLHttpRequest 对象:
iniJavaScript var xhr = new XMLHttpRequest();
-
设置回调函数:
iniJavaScript xhr.onreadystatechange = function() { if (xhr.readyState === 4 && xhr.status === 200) { document.getElementById('result').innerHTML = xhr.responseText; } };
readyState
表示请求的状态,值为 4 表示请求已完成。status
表示 HTTP 状态码,200 表示成功。
-
打开连接:
kotlinJavaScript xhr.open('GET', 'data.json', true);
- 第一个参数是请求类型(GET 或 POST)。
- 第二个参数是请求的 URL。
- 第三个参数表示是否异步,默认为
true
。
-
发送请求:
iniJavaScript xhr.send();
跨域问题
如果 AJAX 请求的目标 URL 与当前页面不在同一个域名下,则会触发同源策略(阻止从一个源加载的脚本访问来自另一个源的资源)限制。此时可以考虑以下几种解决方案:
解决方案 | 方案说明 | 优缺点 |
---|---|---|
CORS(Cross-Origin Resource Sharing) | 服务器通过设置响应头来启用 CORS | 适用于大多数现代浏览器,是最灵活和强大的解决方案。 |
JSONP(JSON with Padding) | 一种利用 <script> 标签绕过同源策略的方法 |
适用于只支持 GET 请求的情况,但安全性较低且功能受限。 |
代理服务器 | 在客户端和目标服务器之间添加一个代理服务器。这个代理服务器运行在同一源上,并转发请求到目标服务器。 | 适用于复杂的应用场景,可以处理各种请求类型。 |
WebSockets | WebSockets 是一种全双工通信协议,不受同源策略限制。 | 适用于实时通信场景。 |
### iframe | 网页内嵌入另一个网页,通过在 iframe 中加载第三方内容,并通过 postMessage 在主窗口和 iframe 之间通信。 | 适用于需要在不同源之间通信的场景。 1. 内容隔离 ,2.灵活的内容展示 3.易于集成外部资源 1.安全性问题 2.同源策略限制 不能直接用js,不能进行太复杂交互3.SEO 影响 不会被搜索引擎很好地索引4.用户体验问题 加载慢,设计不一致5.隐私问题 收集用户浏览数据。SEO 搜索引擎优化 |
1. CORS(Cross-Origin Resource Sharing)
CORS 是一种安全机制,允许服务器声明哪些来源可以访问其资源。服务器通过设置响应头来启用 CORS。 洋葱模型
服务器端设置/Express/JavaScript
const express = require('express');
const cors = require('cors');
const app = express();
// 使用 CORS 中间件
app.use(cors());
app.get('/data', (req, res) => {
res.json({ message: "This is cross-origin data!" });
});
app.listen(3000, () => console.log('Server running on port 3000'));
自定义CORS设置
JavaScript
const corsOptions = {
origin: 'http://example.com', // 允许的源
methods: ['GET', 'POST'], // 允许的方法
allowedHeaders: ['Content-Type'], // 允许的头部
};
app.use(cors(corsOptions));
app.get('/data', (req, res) => {
res.json({ message: "This is custom CORS data!" });
});
2. JSONP(JSON with Padding)
JSONP 利用了 <script>
标签不受同源策略限制的特点,通过动态插入 <script>
标签来获取数据。
客户端代码
HTML
<script>
function handleResponse(data) {
console.log(data.message); // 输出 "This is cross-origin data!"
}
var script = document.createElement('script');
script.src = 'http://otherdomain.com/data?callback=handleResponse';
document.head.appendChild(script);
</script>
服务器端代码
JavaScript
const express = require('express');
const app = express();
app.get('/data', (req, res) => {
const callback = req.query.callback || 'handleResponse';
const data = { message: "This is cross-origin data!" };
res.type('application/javascript'); // 设置 MIME 类型
res.send(`${callback}(${JSON.stringify(data)})`);
});
app.listen(3000, () => console.log('Server running on port 3000'));
3. 使用代理服务器
代理服务器可以帮助你在客户端和目标服务器之间转发请求,从而避免跨域问题。
客户端代码/JavaScript
fetch('/proxy/data')
.then(response => response.json())
.then(data => console.log(data.message)); // 输出 "This is cross-origin data!"
代理服务器设置
JavaScript
const express = require('express');
const request = require('request');
const app = express();
app.get('/proxy/data', (req, res) => {
request('http://otherdomain.com/data', (error, response, body) => {
if (!error && response.statusCode == 200) {
res.json(JSON.parse(body));
} else {
res.status(500).send('Error fetching data');
}
});
});
app.listen(3000, () => console.log('Proxy server running on port 3000'));
4. 使用 WebSockets
WebSockets 是一种全双工通信协议,不受同源策略限制。
客户端代码
ini
JavaScript
const socket = new WebSocket('ws://otherdomain.com/socket');
socket.onopen = () => {
console.log('WebSocket connection established');
socket.send('Hello Server!');
};
socket.onmessage = (event) => {
console.log(`Received from server: ${event.data}`);
};
服务器端代码(Node.js + ws)
javascript
JavaScript
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', (ws) => {
console.log('Client connected');
ws.on('message', (message) => {
console.log(`Received from client: ${message}`);
ws.send('Hello Client!');
});
});
console.log('WebSocket server started on port 8080');
5. 使用 iframe
通过在 iframe 中加载第三方内容,并通过 postMessage 在主窗口和 iframe 之间通信。
主窗口代码
xml
HTML
<iframe id="crossDomainFrame" src="http://otherdomain.com/frame.html"></iframe>
<script>
window.addEventListener('message', (event) => {
if (event.origin !== 'http://otherdomain.com') return; // 安全检查
console.log(event.data); // 输出 "This is cross-domain data!"
}, false);
document.getElementById('crossDomainFrame').contentWindow.postMessage('Hello Frame!', 'http://otherdomain.com');
</script>
iframe 内部代码 (frame.html
)
xml
HTML
<script>
window.addEventListener('message', (event) => {
if (event.origin !== 'http://yourdomain.com') return; // 安全检查
console.log(event.data); // 输出 "Hello Frame!"
event.source.postMessage('This is cross-domain data!', event.origin);
}, false);
</script>