# S3 与 httpfs

> 用 DuckDB 的 httpfs 在 DuckLocal 中查询 Amazon S3 与 S3 兼容存储：配置凭据、浏览 bucket、对远程文件执行 SQL。

Source: https://ducklocal.app/docs/zh/s3

**[English](../s3.md)**

DuckLocal 可以通过 DuckDB 的 `httpfs` 扩展读取 S3 及兼容 S3 的存储中的对象。
在标题栏的 **S3** 按钮中配置。

## 配置凭据

对话框有四个字段：

| 字段 | 默认值 | 说明 |
| --- | --- | --- |
| Endpoint | `s3.amazonaws.com` | 填了 `http://` 就用 HTTP，否则用 HTTPS |
| Region | `us-east-1` | 按输入原样发送 |
| Access Key ID | — | 必填 |
| Secret Access Key | — | 必填，输入时隐藏，可用开关显示 |

确认后执行的语句相当于：

```sql
INSTALL httpfs; LOAD httpfs;
CREATE OR REPLACE SECRET ducklocal_s3 (
  TYPE s3, PROVIDER config,
  KEY_ID '…', SECRET '…',
  REGION '…', ENDPOINT '…'
);
```

**凭据仅在当前会话有效。** 凭据不会写入磁盘；打开或切换数据库时凭据会被清空，需重新配置。目前除重新配置外，没有其他单独清除凭据的方式。

## 浏览

配置完成后，侧栏会出现 **S3** 根节点，内容按需加载：展开根节点列出存储桶，展开存储桶或前缀列出其中的对象。存储桶和前缀按顺序排列，对象显示易读的大小。使用刷新按钮可以重新加载某一层，或在出错后重试。

每层最多列出 **1,000 条**，即使响应表明还有更多条目。
没有进一步的分页，没有前缀过滤框，也没有搜索：
存储桶的某一层超过一千个对象时，列表看起来是完整的，
其实并不完整。

## 查询对象

点击键名带数据文件扩展名的对象，当前编辑器会填入：

```sql
SELECT *
FROM 's3://bucket/key'
LIMIT 100;
```

这就是一条普通查询：数据经 `httpfs` 读取，所以 DuckDB
`read_parquet` / `read_csv_auto` 的行为照样适用，包括下推
（把过滤和列选择下推到文件读取阶段）。
这条查询会替换当前标签页里原有的内容。

只有识别为数据文件的键名才能点击。识别的扩展名与本地文件相同，
见[数据源](data-sources.md#支持的文件格式)页的清单。

## 限制 {#limitations}

- **浏览是只读的。** 浏览器不能上传、下载到文件、删除、复制，
  也不能创建存储桶。查询仍会下载远端数据。
- **不支持会话令牌。** 从不发送 `X-Amz-Security-Token` 请求头，
  所以临时 STS 凭据用不了。请改用长期密钥，
  或只凭 key/secret 就能访问的端点。
- **Endpoint 寻址方式基本是自动的。** S3 URL 访问存储桶有两种寻址方式：
  虚拟主机寻址和路径寻址。主机名包含 `amazonaws.com`
  时用虚拟主机寻址，否则用路径寻址。对自建网关来说，
  这通常正合适；如果某个网关需要另一种寻址方式，
  没有选项可以改。
- 区域填错时，会改用 DuckDB 返回的区域重试一次；
  仍然失败，就原样显示错误。
- 需要联网：首次使用时，`INSTALL httpfs` 会下载扩展。
  浏览会向配置的端点发送 HTTP 或 HTTPS 请求（填 `http://` 时用 HTTP，
  否则用 HTTPS）。请求中包含存储桶名、键前缀等元数据，
  以及签名请求头里的身份验证信息；浏览不会上传本地数据库文件或查询结果。
  查询远端对象时，数据会经 `httpfs` 下载到本机。

## 故障排查

| 现象 | 可能原因 |
| --- | --- |
| 配置后浏览立即失败 | 区域或端点错误；查看侧栏中显示的消息 |
| 自建端点报错 | 寻址方式不对，或该端点要求会话令牌 |
| `httpfs` 安装错误 | 没有网络，或代理阻止了扩展下载 |
| 凭据好像丢了 | 打开或切换了数据库，这会清除凭据（设计如此） |

DuckLocal 打包成签名应用时，加载 `httpfs` 扩展
需要 `com.apple.security.cs.disable-library-validation` 授权；
随附的打包脚本已经加上了这项授权。
