html5静态网页调用API是前端开发中的常见需求,由于浏览器的同源策略限制,直接调用不同域的API会出现跨域错误,需要通过合适的方法处理跨域问题才能完成正常的接口调用。

html5静态网页调用API的基础方式
静态网页调用API本质上是通过JavaScript发起网络请求,html5提供了原生的fetch API和XMLHttpRequest对象来实现这个功能,其中fetch是更现代的方案,语法更简洁。
如果使用fetch调用同域的API,代码实现非常简单,示例如下:
// 同域API调用示例
fetch('/api/user/list')
.then(response => {
// 判断响应状态是否正常
if (!response.ok) {
throw new Error('请求失败,状态码:' + response.status);
}
// 解析JSON格式的响应数据
return response.json();
})
.then(data => {
console.log('获取到的用户列表:', data);
// 处理数据,更新页面内容
})
.catch(error => {
console.error('请求出错:', error);
});
跨域请求产生的原因
浏览器的同源策略要求,只有当请求的协议、域名、端口都和当前页面一致时,才允许正常获取数据。如果静态网页部署在http://localhost:3000,调用的API地址是http://api.ipipp.com,就会出现跨域问题,浏览器会在控制台抛出类似Access-Control-Allow-Origin的错误提示。
常见的跨域请求处理方法
1. CORS(跨域资源共享)
CORS是目前最主流的跨域解决方案,需要后端服务器配合设置响应头,允许指定的前端源访问接口。静态网页端不需要做特殊配置,只需要正常发起请求即可。
后端设置CORS响应头的示例(以Node.js Express框架为例):
const express = require('express');
const app = express();
// 设置CORS响应头
app.use((req, res, next) => {
// 允许的前端源,这里设置为允许所有源,实际开发中可以指定具体域名
res.setHeader('Access-Control-Allow-Origin', '*');
// 允许的请求方法
res.setHeader('Access-Control-Allow-Methods', 'GET,POST,PUT,DELETE,OPTIONS');
// 允许的请求头
res.setHeader('Access-Control-Allow-Headers', 'Content-Type,Authorization');
// 处理预检请求
if (req.method === 'OPTIONS') {
return res.sendStatus(200);
}
next();
});
// 示例API接口
app.get('/api/user/list', (req, res) => {
res.json([
{ id: 1, name: '张三' },
{ id: 2, name: '李四' }
]);
});
app.listen(4000, () => {
console.log('API服务运行在4000端口');
});
静态网页调用这个API的代码和同域调用的代码完全一致,不需要额外修改:
// 调用开启了CORS的跨域API
fetch('http://api.ipipp.com/api/user/list')
.then(response => response.json())
.then(data => console.log('跨域获取到的数据:', data))
.catch(error => console.error('请求出错:', error));
2. JSONP
JSONP是利用script标签没有跨域限制的特性实现的,只支持GET请求,需要后端返回指定格式的响应。这种方案兼容性较好,但安全性较低,目前使用场景越来越少。
静态网页端的JSONP实现示例:
// 定义处理返回数据的回调函数
function handleUserData(data) {
console.log('JSONP获取到的数据:', data);
}
// 创建script标签,发起JSONP请求
const script = document.createElement('script');
// 请求地址后面带上回调函数名参数
script.src = 'http://api.ipipp.com/api/user/list?callback=handleUserData';
// 将script标签添加到页面中
document.body.appendChild(script);
// 请求完成后移除script标签
script.onload = () => {
document.body.removeChild(script);
};
对应的后端响应需要把数据包裹在回调函数调用中,示例如下:
// Node.js Express后端JSONP响应示例
app.get('/api/user/list', (req, res) => {
const callbackName = req.query.callback;
const data = [
{ id: 1, name: '张三' },
{ id: 2, name: '李四' }
];
// 返回回调函数调用的字符串
res.send(`${callbackName}(${JSON.stringify(data)})`);
});
3. 代理服务器
如果无法修改后端配置,也可以通过代理服务器转发请求。静态网页先请求同域的代理接口,代理接口再请求目标API,返回结果给静态网页,这样就绕过了浏览器的同源策略限制。
以Nginx作为代理服务器的配置示例:
server {
listen 3000;
server_name localhost;
# 静态网页部署目录
root /path/to/static/page;
index index.html;
# 代理API请求
location /api/ {
proxy_pass http://api.ipipp.com/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
配置完成后,静态网页只需要调用/api/user/list这个同域地址,Nginx会自动转发到http://api.ipipp.com/api/user/list,静态网页的调用代码和同域调用完全一致。
4. postMessage
如果是不同窗口之间的跨域通信,比如静态网页嵌套了不同域的iframe,需要获取iframe里的数据,可以使用postMessage方法。这种方案适用于页面之间有嵌套关系的场景。
父页面发送请求并接收消息的示例:
// 父页面代码
const iframe = document.getElementById('targetIframe');
// 向iframe发送请求消息
iframe.contentWindow.postMessage({
type: 'GET_USER_LIST',
params: {}
}, 'http://api.ipipp.com');
// 监听iframe返回的消息
window.addEventListener('message', (event) => {
// 验证消息来源是否合法
if (event.origin !== 'http://api.ipipp.com') return;
if (event.data.type === 'USER_LIST_RESULT') {
console.log('通过postMessage获取到的数据:', event.data.data);
}
});
iframe页面接收消息并返回数据的示例:
// iframe页面代码
window.addEventListener('message', (event) => {
// 验证消息来源
if (event.origin !== 'http://localhost:3000') return;
if (event.data.type === 'GET_USER_LIST') {
// 调用自身的API获取数据
fetch('/api/user/list')
.then(response => response.json())
.then(data => {
// 向父页面返回数据
event.source.postMessage({
type: 'USER_LIST_RESULT',
data: data
}, event.origin);
});
}
});
不同跨域方案的适用场景对比
可以通过下面的表格快速选择适合自己项目的跨域方案:
| 方案名称 | 支持请求方法 | 是否需要后端配合 | 适用场景 |
|---|---|---|---|
| CORS | 所有HTTP方法 | 是 | 现代浏览器环境,后端可配置的场景,首选方案 |
| JSONP | 仅GET | 是 | 需要兼容老版本浏览器,且只需要GET请求的场景 |
| 代理服务器 | 所有HTTP方法 | 否(需要配置代理) | 无法修改后端配置,可部署代理服务的场景 |
| postMessage | 自定义 | 否(需要页面通信配合) | 不同窗口、iframe之间的跨域数据通信场景 |
注意事项
- 生产环境中设置CORS的Access-Control-Allow-Origin尽量不要用
*,应该指定具体的前端域名,避免安全风险。 - JSONP只能发送GET请求,且存在XSS攻击风险,不建议在新项目中使用。
- 使用代理服务器时,要注意代理转发的地址正确,避免转发到恶意地址。
- 如果调用的是需要携带Cookie的跨域API,需要设置
credentials: 'include'参数,同时后端需要设置Access-Control-Allow-Credentials为true,且Access-Control-Allow-Origin不能为*。
通过以上方法,开发者可以根据实际的项目情况选择合适的跨域处理方案,顺利实现html5静态网页调用API的需求。