# 短链接（Short Link）说明

`alien-store` 模块提供「长链 → 短链 → 302 跳转」能力，供前端生成微信分享等场景的短 URL。映射存储在 **Redis**，键前缀为 `short:link:`。

## 接口

| 方法 | 路径 | 说明 |
|------|------|------|
| `POST` | `/store/short-link/shorten` | 请求体：`{"longUrl":"<完整长链接>"}`，成功返回 `shortUrl`、`code` |
| `GET` | `/store/short-link/s/{code}` | 返回 `R<ShortLinkResolveResponse>`，其中 `data.longUrl` 为原始长链；失败为业务失败文案 |
| `GET` | `/store/short-link/s/{code}/open` | **302** 跳转至长链（浏览器直开/书签）；不存在或过期 **404** |

网关需将上述路径路由到 `alien-store`。JSON 接口的返回体为项目统一的 `R<T>`。

**说明**：分享出去的短链地址一般为 `…/store/short-link/s/{code}`。若在微信内由 **小程序 / H5 请求**解析，请调 **`GET /s/{code}`** 取 `longUrl` 后再 `navigateTo` 或 `location.replace`。若需 **系统浏览器打开即跳**，可把分享链指向 **`/s/{code}/open`**，或继续用原短链前缀但由落地页先请求 `/s/{code}` 再跳转。

## 配置项

| 配置键 | 说明 | 默认值 |
|--------|------|--------|
| `short-link.public-base-url` | 对外短链前缀（**无尾斜杠**），须含协议与端口（若有）。含网关 `context-path` 时写全 | 空（未配置时生成接口会报错） |
| `short-link.allowed-hosts` | 允许被缩短的**长链**域名白名单，逗号分隔（小写 host）。**空**表示不按白名单限制（仍会拦截内网，除非开发开关打开） | 空 |
| `short-link.https-only` | 长链是否**仅允许 https** | `true` |
| `short-link.allow-local-network-target` | 是否允许长链指向 localhost / 内网 IP。**仅本地开发** | `false` |
| `short-link.ttl-days` | Redis 中映射保留天数 | `30` |

生成的完整短链形如（解析用第一段 URL 即可；若需 302 直达可加 `/open`）：

`{short-link.public-base-url}/store/short-link/s/{code}`

## 各环境推荐配置

### 开发环境（dev）

适合本机或内网联调；长链可能是 `http://127.0.0.1`、`192.168.x`。

```yaml
short-link:
  public-base-url: http://127.0.0.1:8080
  https-only: false
  allow-local-network-target: true
  allowed-hosts:
  ttl-days: 30
```

手机同 WiFi 联调时，将 `public-base-url` 改为 **`http://<本机局域网IP>:端口`**。微信内打开需可访问该地址；公网联调可用 ngrok 等穿透，将前缀改为穿透提供的 `https://...`。

### 测试环境（test / sit）

```yaml
short-link:
  public-base-url: https://test.ailien.shop
  https-only: true
  allow-local-network-target: false
  allowed-hosts: test.ailien.shop,www.test.ailien.shop,m.test.ailien.shop
  ttl-days: 30
```

若测试环境暂无 HTTPS，可临时 `https-only: false`，**不要**在生产打开 `allow-local-network-target`。

### 预生产环境（uat / pre）

与生产策略一致，仅换预发域名。

```yaml
short-link:
  public-base-url: https://uat.ailien.shop
  https-only: true
  allow-local-network-target: false
  allowed-hosts: uat.ailien.shop,www.uat.ailien.shop,m.uat.ailien.shop
  ttl-days: 30
```

### 生产环境（prod）

```yaml
short-link:
  public-base-url: https://prod.ailien.shop
  https-only: true
  allow-local-network-target: false
  allowed-hosts: prod.ailien.shop,www.prod.ailien.shop,m.prod.ailien.shop
  ttl-days: 30
```

生产环境**必须** `allow-local-network-target: false`，并**强烈建议**配置 `allowed-hosts`，缩小开放重定向面。

## Nacos 建议

- 各环境差异项（`public-base-url`、`allowed-hosts`、`https-only`、`allow-local-network-target`）放在对应环境的 data-id（如 `alien-store-dev.yml`、`alien-store-prod.yml`）。
- 共性项（如 `ttl-days`）可放在 `common.yml`。

## 相关代码

| 类型 | 路径 |
|------|------|
| Controller | `shop.alien.store.controller.ShortLinkController` |
| Service | `shop.alien.store.service.impl.ShortLinkServiceImpl` |
| 工具 | `shop.alien.store.util.Base62Util`、`shop.alien.store.util.ShortLinkUrlValidator` |
| DTO | `shop.alien.store.dto.ShortLinkShortenRequest`、`ShortLinkShortenResponse` |

## 安全说明

- 长链会做基本校验：协议、长度、（可选）域名白名单、内网地址拦截（可通过 `allow-local-network-target` 在**仅开发**放开）。
- 跳转接口为公开访问，请勿在生产开启 `allow-local-network-target`。
