JavaScript fetch调用Grafana Loki Cloud接口遇权限及CORS问题求助
问题场景
我尝试从Grafana Loki Cloud查询数据,以下curl命令可正常运行:
curl -s -G "https://<user>:<API key>@<site>.grafana.net/loki/api/v1/query_range" --data-urlencode 'query={job="maplejob"}'
凭证置于链接中的报错
改写为JavaScript代码后出现报错:
const query_url = new URL('https://<user>:<API key>@<site>.grafana.net/loki/api/v1/query_range'); const params = new URLSearchParams(query_url.search); params.set('query', '{job="maplejob"}'); query_url.search = params; fetch(query_url.toString(), {}) .then((response) => { console.log(response) }) .catch(console.error);
错误信息:
TypeError: Failed to execute 'fetch' on 'Window': Request cannot be constructed from a URL that includes credentials
凭证置于请求头中的报错
调整为将凭证放在请求头后,仍出现CORS相关报错:
const query_url = new URL('https://<site>.grafana.net/loki/api/v1/query_range'); const params = new URLSearchParams(query_url.search); params.set('query', '{job="maplejob"}'); query_url.search = params; fetch(query_url.toString(), { headers: { 'Authorization': `Basic ${btoa('<user>:<API key>')}` }, }) .then((response) => { console.log(response) }) .catch(console.error);
错误信息:
Access to fetch at '
' from origin ' ' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.
解决方法
1. 后端代理(推荐方案)
浏览器的CORS限制是安全机制,无法直接绕过,最可靠的方式是通过自己的后端服务转发请求:
- 前端向自己的后端发送查询请求,不直接调用Loki Cloud API
- 后端使用服务器端请求(不受浏览器CORS限制)调用Loki Cloud,携带凭证完成查询
- 后端将Loki返回的数据转发给前端
示例Node.js后端(Express框架):
const express = require('express'); const axios = require('axios'); const app = express(); const port = 3000; // 配置跨域允许(或使用cors中间件) app.use((req, res, next) => { res.header('Access-Control-Allow-Origin', '<你的前端域名>'); res.header('Access-Control-Allow-Methods', 'GET, OPTIONS'); res.header('Access-Control-Allow-Headers', 'Content-Type'); next(); }); // 封装Loki查询接口 app.get('/api/loki-query', async (req, res) => { try { const query = req.query.query; const lokiUrl = new URL('https://<site>.grafana.net/loki/api/v1/query_range'); lokiUrl.searchParams.set('query', query); // 发起服务器端请求,携带Loki凭证 const response = await axios.get(lokiUrl.toString(), { auth: { username: '<user>', password: '<API key>' } }); res.json(response.data); } catch (error) { res.status(error.response?.status || 500).json({ error: error.message || '查询失败' }); } }); app.listen(port, () => { console.log(`代理服务运行在端口 ${port}`); });
前端调用代码:
fetch('http://你的后端域名:3000/api/loki-query?query={job="maplejob"}') .then(res => res.json()) .then(data => console.log(data)) .catch(console.error);
2. 检查Grafana Cloud CORS配置(可选)
登录Grafana Cloud控制台,查看是否支持将你的前端域名添加到CORS白名单。但注意Loki Cloud的公开API通常默认不开放自定义CORS配置,此方案不一定可行。
关于URL带凭证报错的说明
浏览器的fetch API出于安全考虑,禁止直接使用包含用户名和密码的URL发起请求,因此第一种写法必然报错,必须改用后端代理或Authorization头(但Authorization头会触发CORS预检,仍需后端配合)。
内容的提问来源于stack exchange,提问作者user22009348

