希望你一切都好
我在使用 flutter web 时遇到问题。我尝试向 https://timeapi.io/api/TimeZone/zone?timeZone=Europe/Amsterdam 发出 API REST 请求以获取特定位置的时间,但收到此错误 XMLHttpRequest error 并且在浏览器中显示控制台时,出现此错误(下图)
经过几天的研究,我知道这是 CORS,并且我能够测试一些解决方案,但没有成功。
这是我能做的:
Future<void> _getCurrentDateTime() async {
try {
var url = Uri.https('timeapi.io', 'TimeZone/zone', {'timeZone': 'Europe/Amsterdam'});
final headers = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "POST, GET, OPTIONS, DELETE",
"Origin": "https://localhost"
};
var response = await http.get(url, headers: headers);
log('Response status: ${response.statusCode}');
log('Response body: ${response.body}');
// return now;
} catch (e) {
rethrow;
}
}
如何解决这个错误?谢谢
您缺少
/api/
作为行中网址的一部分:
var url = Uri.https('timeapi.io', 'TimeZone/zone', {'timeZone': 'Europe/Amsterdam'});
如果您注意到控制台上出现错误,您会发现打印的 URL 中也缺少
api
。
最终会出现 404 错误,如果您在浏览器中打开 https://timeapi.io/TimeZone/zone?timeZone=Europe/Amsterdam,您会发现 404 响应。
因此,404 响应中不包含 CORS 标头,从而导致您在浏览器控制台上看到 CORS 错误。
如果您想致电 https://timeapi.io/api/TimeZone/zone?timeZone=Europe/Amsterdam
代码应该是
var url = Uri.https('timeapi.io', 'api/TimeZone/zone', {'timeZone': 'Europe/Amsterdam'});
此外,您可能想要删除这些标头,因为它们应该是从后端而不是前端发送的。以下几行代码是多余的。
final headers = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "POST, GET, OPTIONS, DELETE",
"Origin": "https://localhost"
};
您收到 CORS 错误的原因是时间 API 未返回正确的 CORS 标头 (
Access-Control-Allow-Origin
)。
curl -s -D - -o /dev/null 'https://timeapi.io/api/TimeZone/zone?timeZone=Europe/Amsterdam'
HTTP/1.1 200 OK
Server: nginx/1.27.0
Date: Tue, 14 Jan 2025 06:34:25 GMT
Content-Type: application/json; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
为了解决此问题,您将需要某种后端,可以是您自己的后端,也可以使用诸如 CORS 代理之类的服务。
您可以将 Web 获取到后端,而不是直接在 Flutter Web 中获取时间 API。然后您的后端可以有一个获取时间 API 的端点。
它看起来像这样,示例在 Express 中,但您需要将其适应您的后端。
const app = express()
// use if backend and frontend in different origin
const cors = require('cors')
app.use(cors())
app.get('/time', (req, res) => {
fetch('https://timeapi.io/api/TimeZone/zone?timeZone=Europe/Amsterdam')
.then(response => response.json())
.then(data => res.json(data));
});
Flutter Web 代码如下
Future<void> _getCurrentDateTime() async {
try {
var url = Uri.parse('<YOUR_BACKEND_URL>/time');
var response = await http.get(url);
log('Response status: ${response.statusCode}');
log('Response body: ${response.body}');
// return now;
} catch (e) {
rethrow;
}
}
如果您没有后端,您仍然可以通过使用 CORS 代理来达到相同的结果。它的工作方式与将您的请求转发到后端的方式相同。您不是直接获取目标 API,而是获取代理,然后代理会将您的请求转发到目标 API。然后,代理将使用适当的标头将响应返回给您。 您可以使用自托管 (cors-anywhere) 或托管 CORS 代理 (Corsfix) 选项。
这是它的样子
Future<void> _getCurrentDateTime() async {
try {
var url = Uri.parse(
'https://proxy.corsfix.com/?https://timeapi.io/api/TimeZone/zone?timeZone=Europe/Amsterdam',
);
var response = await http.get(url);
log('Response status: ${response.statusCode}');
log('Response body: ${response.body}');
} catch (e) {
rethrow;
}
}
这样您就可以从时间 API 获取结果,而不必处理 CORS 错误。
(我隶属于 Corsfix)