- 实验背景:
我目前有一台服务器A,和一台主机B,两台设备属于同一局域网,相互之间可以通讯。服务器A中部署着clickhouse,我在主机B中想直接通过javascript代码访问服务器中的clickhouse数据库并获取数据。- ClickHouse 服务器:192.168.0.10(局域网 IP)
- 运行在 Docker,端口默认:8123(HTTP 端口)
- 浏览器前端页面运行在:192.168.0.11 的某个网页中
- 你希望用 JS 代码直接执行 SQL 查询,比如获取某个用户轨迹
- 环境说明:
- 服务器A(ip:192.168.0.10):通过docker的形式部署了一个clickhouse容器,并开放其8123端口。用户名为Micheal,密码为空。
- 主机B(ip:192.168.0.11):与A属于同一局域网,可以用DBeaver连接到A中部署的Clickhouse数据库。
操作步骤
step1:校验性工作
- 校验1:Clickhouse的HTTP接口是否可访问。
在浏览器中访问:http://192.168.0.10:8123
,看到 Ok.即可
或者在命令行中输入:curl http://192.168.0.10:8123
,看到 Ok.即可意外情况1:如果A中访问不了,则可能是容器没开启,或者端口号未映射到宿主机上。
意外情况2:如果A中访问正常,B中访问异常,则可能有以下3个原因:
1)主机B用了梯子,导致地址与A不在一个局域网了。
2)Docker没正确映射端口(去核查docker容器,输入:docker ps,查看是否有类似行0.0.0.0:8123->8123/tcp
或者192.168.0.10:8123->8123/tcp
,如果是127.0.0.1:8123->8123/tcp
那么这说明端口只绑定在本地回环地址,局域网访问不了!)
3)防火墙拦截了请求。(去A中开放它:sudo ufw allow 8123) - 校验2: 测试 SQL 查询接口
curl -X POST "http://192.168.0.10:8123/" --data "SELECT 1"
应该输出为:1
如果不通,可能原因:问题 解决方法 没有暴露端口 启动容器时加上 -p 8123:8123 防火墙阻止了端口 sudo ufw allow 8123 或检查安全组设置 ClickHouse 没启动或报错 docker logs clickhouse 查看日志 宿主机用的是私有 IP 被隔离 确保局域网中其他机器能访问 192.168.0.10
step2:通过nginx设置反向代理(目的:希望前端 JS 通过访问 http://192.168.0.10/clickhouse/ 获取数据)
在A中配置nginx代理
-
1)创建nginx配置文件(用于支持CORS)
# 在服务器的某个目录(比如 /xxx/xxx/xxx)中创建: mkdir -p /xxx/conf.d # 创建配置文件 clickhouse.conf: vim /xxx/conf.d/clickhouse.conf
在clickhouse.conf文件中写入如下内容:(注意,改成你自己的服务器IP地址)
server { listen 80; server_name localhost; location /clickhouse/ { proxy_pass http://192.168.0.10:8123/; # 你的服务器IP地址 # 屏蔽后端 clickhouse 自带的 CORS 头,避免重复 proxy_hide_header Access-Control-Allow-Origin; proxy_hide_header Access-Control-Allow-Methods; proxy_hide_header Access-Control-Allow-Headers; # OPTIONS 预检请求 if ($request_method = OPTIONS) { add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Methods "GET, POST, OPTIONS"; add_header Access-Control-Allow-Headers "Content-Type, Authorization"; add_header Access-Control-Max-Age 86400; add_header Content-Length 0; add_header Content-Type text/plain; return 204; } # 正常请求添加 CORS 头 add_header Access-Control-Allow-Origin * always; add_header Access-Control-Allow-Methods "GET, POST, OPTIONS" always; add_header Access-Control-Allow-Headers "Content-Type, Authorization" always; } }
-
2)创建nginx容器,将A中的80端口映射
docker run -d \ --name nginx-clickhouse \ -p 80:80 \ -v /xxx/conf.d:/etc/nginx/conf.d \ nginx
说明:
-v 把你刚写的配置文件挂载到 nginx 中
-p 80:80 把 nginx 容器的 80 端口暴露出来- 也可以先创建docker容器,然后再创建容器中的配置文件(/etc/nginx/conf.d/clickhouse.conf),并进行修改。
- 改完以后记得重启nginx(
sudo nginx -s reload
)或者重启docker容器(docker restart nginx-clickhouse
)
-
3)在命令行测试nginx 是否转发成功
-
测试1)测试 CORS 头是否返回
再次使用 curl 或浏览器开发者工具测试 CORS 配置是否生效:curl -X OPTIONS http://192.168.0.10/clickhouse/ -i
你应该看到类似以下响应头:
HTTP/1.1 204 No Content Server: nginx/1.19.3 Date: <timestamp> Access-Control-Allow-Origin: * Access-Control-Allow-Methods: GET, POST, OPTIONS Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With Access-Control-Max-Age: 1728000
-
测试2)测试代理是否生效
curl -X POST "http://192.168.0.10/clickhouse/" --data "SELECT 1"
应返回:1。说明代理和 ClickHouse 通了。
-
step3: 编写测试代码
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>ClickHouse SQL 查询页面</title>
<style>
body { font-family: sans-serif; padding: 2em; }
textarea { width: 100%; height: 100px; }
pre { background: #f4f4f4; padding: 1em; white-space: pre-wrap; }
</style>
</head>
<body>
<h2>ClickHouse 查询测试</h2>
<textarea id="sql">SELECT now(), version()</textarea><br><br>
<button onclick="query()">执行 SQL</button>
<h3>结果:</h3>
<pre id="output">点击按钮开始查询...</pre>
<script>
async function query() {
const sql = document.getElementById('sql').value;
const output = document.getElementById('output');
output.textContent = '查询中...';
try {
const response = await fetch('http://192.168.0.10/clickhouse/', { //改成你自己的服务器IP地址
method: 'POST',
headers: {
'Content-Type': 'text/plain',
'Authorization': 'Basic ' + btoa('user_name:') // 添加密码(如有): btoa('default:password')
},
body: sql
});
const text = await response.text();
output.textContent = text;
} catch (err) {
output.textContent = '请求失败: ' + err;
}
}
</script>
</body>
</html>