REST API 请求 Flutter Web CORS 问题

问题描述 投票:0回答:2

希望你一切都好

我在使用 flutter web 时遇到问题。我尝试向 https://timeapi.io/api/TimeZone/zone?timeZone=Europe/Amsterdam 发出 API REST 请求以获取特定位置的时间,但收到此错误 XMLHttpRequest error 并且在浏览器中显示控制台时,出现此错误(下图)

enter image description here

经过几天的研究,我知道这是 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 rest http cors flutter-web
2个回答
0
投票

您缺少

/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"
};

0
投票

您收到 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 代理

如果您没有后端,您仍然可以通过使用 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)

© www.soinside.com 2019 - 2024. All rights reserved.