JavaScript调用ClickHouse遇ERR_EMPTY_RESPONSE及CORS问题求助
解决Chrome中JS请求ClickHouse的CORS及认证问题
问题核心原因
- 内网仍会触发浏览器CORS检查:只要是浏览器环境(Chrome),跨源请求(即使是内网不同服务)都会执行CORS策略,和是否在企业内网无关。
- 错误的请求头设置:你代码里的
Access-Control-Allow-Origins是响应头,只能由服务器返回,放在请求头里不仅无效,还会让浏览器认为这是非简单请求,触发OPTIONS预检请求。而ClickHouse默认没处理OPTIONS请求,直接返回空响应,导致ERR_EMPTY_RESPONSE。 no-cors模式的限制:开启这个模式后,浏览器会强制屏蔽所有自定义请求头(包括Authorization),所以服务器收不到你的认证信息,返回403。
无需修改ClickHouse的解决方案
方案1:调整请求头,避免触发预检请求
ClickHouse的GET查询不需要Content-Type: application/json,Postman能成功大概率是没加这个头。把这个不必要的请求头去掉,让请求变成浏览器认可的简单请求,就不会触发预检:
async function getDataFromClickHouse () { const _baseUrl = 'http://servername:8123/'; const _username = 'login'; const _password = 'password'; const _query = 'SELECT * FROM any_table'; const base64Credentials = btoa(`${_username}:${_password}`); const url = `${_baseUrl}/?query=${encodeURIComponent(_query)}`; try { const response = await fetch(url, { method: 'GET', headers: { 'Authorization': `Basic ${base64Credentials}` // 去掉Content-Type和无效的Access-Control-Allow-Origins } }); if (response.ok) { // 注意:ClickHouse默认返回TSV格式,不是JSON,直接用response.json()会报错 // 改成获取文本后自行解析,或者在查询里指定FORMAT JSON const rawData = await response.text(); // 如果要JSON格式,修改_query为'SELECT * FROM any_table FORMAT JSON' return rawData; } else { throw new Error(`Error executing ClickHouse query: ${response.statusText}`); } } catch (error) { console.error(error); } }
补充:ClickHouse的GET请求默认返回TSV(制表符分隔)格式,如果你要JSON,记得在查询末尾加FORMAT JSON,这样才能用response.json()解析。
方案2:用Nginx做反向代理(生产环境推荐)
在前端和ClickHouse之间加一层Nginx代理,由Nginx处理CORS并转发请求,完全不用修改ClickHouse配置:
server { listen 8080; server_name localhost; location /clickhouse/ { # 转发请求到ClickHouse proxy_pass http://servername:8123/; proxy_set_header Authorization $http_authorization; # 添加CORS响应头 add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Methods GET,OPTIONS; add_header Access-Control-Allow-Headers Authorization; # 处理OPTIONS预检请求 if ($request_method = OPTIONS) { return 204; } } }
然后前端请求地址改成http://localhost:8080/clickhouse/?query=...,这样浏览器的跨源请求就会被Nginx的CORS头允许。
方案3:开发环境临时关闭Chrome的CORS检查
只适合本地开发测试,生产环境不能用:
- Windows:在命令行执行
chrome.exe --disable-web-security --user-data-dir="C:/ChromeDevSession" - macOS:执行
open -n -a "Google Chrome" --args --disable-web-security --user-data-dir="/tmp/ChromeDevSession" - Linux:执行
google-chrome --disable-web-security --user-data-dir="/tmp/ChromeDevSession"
注意:这个会关闭Chrome的所有安全检查,不要用这个窗口浏览其他网站,仅限开发测试。
内容的提问来源于stack exchange,提问作者Артём Пучков
相关产品推荐
相关产品推荐

