小众网

概述与约定

小众网的网站接口直接由 nginx 内部的 njs 提供,没有独立后端进程。所有接口遵循统一的 /控制器/动作[/参数] 路由规则。端点有两种:现代设备用 https://wap.iniche.cn, 复古 / 老设备(不支持 HTTPS 或 TLS)可用明文 http://wap.iniche.cn——两者接口与数据完全一致,仅传输层不同。 下文示例统一以 https 端点书写,把 https:// 换成 http:// 即适用于老设备。

  • 统一端点:现代设备 https://wap.iniche.cn;复古 / 老设备 http://wap.iniche.cn。 下文所有相对路径都拼在它后面,例如 https://wap.iniche.cn/app/list
  • JSON 开关:在 GET 请求头加 AJAX: 1 可拿到 JSON 响应,否则返回整页 HTML。 凡是支持程序化读取的接口,建议统一带此头。
  • 认证:登录态保存在 Cookie _auth_2026_2(HttpOnly)。写操作(发帖 / 回帖 / 签到 / 上传 / 评论)与下载安装包需要登录 + 会员 / VIP
  • CSRF:所有 POST / PUT / DELETE 必须在请求头 X-CSRF-Token 携带令牌(或表单字段 _csrf)。令牌与登录会话绑定,有效期 1 小时。
  • 限流:发帖 / 回帖 60 秒内各最多 10 次;搜索 60 秒内最多 20 次;另有按用户等级每日额度(主题 / 回帖 / 上传 / 下载)。

端点选择:现代设备用 https://wap.iniche.cn(加密传输); 复古 / 老设备若无法建立 HTTPS 连接,改用明文 http://wap.iniche.cn 即可(接口、字段、鉴权方式完全相同)。 写操作(发帖 / 回帖 / 签到)通过 http 传输时 Cookie 与 CSRF 令牌以明文发送,仅在可信的老设备本地网络环境下使用。

路由补充:路径中段若是纯数字,会当作 idpage。例如 /subject/5/reply → 主题 5 的回复动作;/app/list/2 → 应用列表第 2 页。

认证与 CSRF

写操作需先登录并取得 CSRF 令牌。流程如下:

  1. 拿会话与令牌:GET 任意页面(如 /user/login),保存 Cookie(含会话),并从响应头 X-CSRF-Token 读取令牌。
  2. 登录:POST /user/login,表单含 emailpassword(登录码)、remember,响应会下发 _auth_2026_2 Cookie。
  3. 每次写操作前刷新令牌:用已登录的 Cookie 再 GET 一次目标页面,读取新的 X-CSRF-Token 随请求回传。
# 1) 取会话 + 首次 CSRF 令牌(读响应头)
curl -s -c cookies.txt -D - "https://wap.iniche.cn/user/login" -o /dev/null
TOKEN=$(curl -s -I "https://wap.iniche.cn/user/login" -b cookies.txt | grep -i '^x-csrf-token:' | awk '{print $2}' | tr -d '\r')

# 2) 登录(POST,携带 cookie 与 CSRF 令牌)
curl -s -b cookies.txt -c cookies.txt -X POST "https://wap.iniche.cn/user/login" \
  -H "X-CSRF-Token: $TOKEN" \
  --data-urlencode "email=you@example.com" \
  --data-urlencode "password=YOUR_LOGIN_CODE" \
  --data-urlencode "remember=1"

# 3) 写操作前,用已登录会话取“新” CSRF 令牌(绑定到登录后的 uid)
TOKEN=$(curl -s -I "https://wap.iniche.cn/forum/1/write" -b cookies.txt | grep -i '^x-csrf-token:' | awk '{print $2}' | tr -d '\r')

CSRF 令牌与会话 uid绑定且 1 小时有效。务必用同一次会话的 Cookie去取令牌、再带同一 Cookie 发请求;换会话或令牌过期都会返回 403。

暂不支持 OAuth 的设备端脚本登录(需处理 oauth_csrf 流程),请使用「邮箱 + 登录码」方式。

版块列表

获取全站板块列表(浏览类,公开)。

  • 端点GET /forum
  • 权限:公开(无需登录)。

响应(AJAX: 1):{ forums:[{id, name, description, subject_count, post_count, icon}] }

curl -s "https://wap.iniche.cn/forum" -H "AJAX: 1"

主题列表

获取某板块下的主题(帖子)列表,支持分页与分类筛选(浏览类,公开)。

  • 端点GET /forum/<forum_id>[/<page>]?category_id=<分类id>
  • 权限:公开(无需登录)。

响应(AJAX: 1):{ subjects:[…], pager:{page,pagesize,total} }。 每条主题含 id, subject, post_count, created_at, last_post_time, is_sticky, is_closed, is_essence, category_id, author_id, author_name, category_name, like_count

# 第 1 页
curl -s "https://wap.iniche.cn/forum/1" -H "AJAX: 1"

# 第 2 页,带分类筛选
curl -s "https://wap.iniche.cn/forum/1/2?category_id=3" -H "AJAX: 1"

回复列表

获取某主题下的回复(含楼中楼)。回复与主题在同一接口返回,没有独立的「回复列表」端点(浏览类,公开)。

  • 端点GET /subject/<subject_id>[/<page>]
  • 权限:公开(无需登录)。

响应(AJAX: 1):{ subject, posts:[…], pager:{page,pagesize,total} }posts 为顶层回复;每条含 replies:[…] 楼中楼,字段与顶层一致: id, post, html, created_at, show_attachments, user_id, nickname, group_id, group_name, like_count, likedpagesize 固定 15

# 第 1 页
curl -s "https://wap.iniche.cn/subject/5" -H "AJAX: 1"

# 第 2 页
curl -s "https://wap.iniche.cn/subject/5/2" -H "AJAX: 1"

发帖(发布主题)

在指定板块发布新主题。

  • 端点POST /forum/<forum_id>/write(如不带板块 id,可用 POST /forum/write 并在表单带 forum_id)。
  • 权限:登录 + 会员(FORUM_write)。
  • 限流:60s 最多 10 次;另受每日主题额度限制。
参数必填说明
subject标题,≤ 200 字符
content正文,≤ 3000 字符,支持 Markdown
forum_id二选一板块 id(路径未带时必填)
category_id板块下的分类 id
show_attachments0/1,是否展示正文附件

响应:成功返回 302 跳转到新主题 /subject/<newId>(该动作无独立 JSON 分支,建议取 Location 头拿到新主题 id)。

curl -s -b cookies.txt -c cookies.txt -X POST "https://wap.iniche.cn/forum/1/write" \
  -H "X-CSRF-Token: $TOKEN" \
  --data-urlencode "subject=怀旧诺基亚主题分享" \
  --data-urlencode "content=这是正文,支持 **Markdown**。"

回帖(回复主题)

在指定主题下发表回复,支持楼中楼。

  • 端点POST /subject/<subject_id>/reply
  • 权限:登录 + 会员(SUBJECT_reply);主题已关闭则返回 403。
  • 限流:60s 最多 10 次;另受每日回帖额度限制。
参数必填说明
content回复正文,≤ 3000 字符,支持 Markdown
parent_id楼中楼:指向某条回复 id;省略则为顶层回复
show_attachments0/1,是否展示附件

响应:带 AJAX: 1 时返回 JSON { "ok": true, "post": { "id", "subject_id", "user_id", "post", "html", "parent_id", "created_at", "nickname" }, "parent_id": <number|null> }; 不带则 302 跳转主题末页。

# 顶层回复
curl -s -b cookies.txt -c cookies.txt -X POST "https://wap.iniche.cn/subject/5/reply" \
  -H "X-CSRF-Token: $TOKEN" -H "AJAX: 1" \
  --data-urlencode "content=沙发,支持一下!"

# 楼中楼(回复某条回复 id=88)
curl -s -b cookies.txt -c cookies.txt -X POST "https://wap.iniche.cn/subject/5/reply" \
  -H "X-CSRF-Token: $TOKEN" -H "AJAX: 1" \
  --data-urlencode "content=同感" --data-urlencode "parent_id=88"

筛选 / 搜索应用

应用库支持按平台 / 分类 / 分辨率等结构化筛选,也可用关键词全文搜索。两者均公开(无需登录)。

A. 结构化筛选 GET /app/list[/<page>]?platform=&sysVer=&category=&resolution=&uploader=&sort=

参数说明
platform平台,如 symbian / j2me / mrp / android / meego / wqx
sysVer系统版本
category分类
resolution分辨率
uploader上传者 userId(须为数字)
sort排序:download(默认)/ date / comment / size
page页码,每页 20 条

响应(AJAX: 1):{ apps:[…], platforms, sysVers, categories, resolutions, pager:{page,pagesize,total}, sort }。 每条 app 含 id, name, chinese_name, version, vendor, platform, sys_ver, category, resolution, description, hash1, ext, size, user_id, download_count, comment_count, uploader_name

B. 关键词搜索 GET /search/<page>?q=<关键词>&type=apps&platform=&category=&resolution=&sysVer=

响应(AJAX: 1):{ q, type, results:[…应用…, screenshots:[{user_id,hash1}]], pager, platforms, categories, resolutions, sysVers, filters }。 限流:60s 最多 20 次。

# 筛选:Android 平台、按下载量排序,第 1 页
curl -s "https://wap.iniche.cn/app/list?platform=android&sort=download" -H "AJAX: 1"

# 搜索:关键词“计算器”,按 apps 类型
curl -s "https://wap.iniche.cn/search/1?q=%E8%AE%A1%E7%AE%97%E5%99%A8&type=apps" -H "AJAX: 1"

查看应用详情

获取单个应用的完整信息与评论。

  • 端点GET /app/<id>?cp=<评论页>&sort=old
  • 权限:公开(无需登录)。

响应(AJAX: 1):{ app:{…}, screenshots:[{id, hash1, user_id}], related, relatedCat, relatedUploader, similar, comments, commentTotal, commentPager, commentSort }appuser_id, hash1, ext, size, download_count, comment_count, vendor, version, platform, category, resolution, sys_ver, description, chinese_name 等字段。

curl -s "https://wap.iniche.cn/app/123?cp=1" -H "AJAX: 1"

下载应用

下载某个应用的安装包。该动作经 nginx 内部跳转后由 nginx 直接以二进制流出,不进 njs 内存。

  • 端点GET /app/<id>/download → 内部跳转到 /download/<user_id>/<hash1>.<ext>
  • 权限:登录 + 有效 VIP(管理员 / 版主豁免);免费会员直接 403。
  • 鉴权:真正的校验在 nginx location /download/auth_request /app/auth:校验登录态 + VIP 每日配额,并下发友好文件名(Content-Disposition: attachment)。失败时 403 跳转到 /app/nopass 友好页。
# 需带登录态 cookie;-L 跟随内部跳转;-o 指定保存文件名
curl -s -b cookies.txt -L "https://wap.iniche.cn/app/123/download" -o MyApp.sis

# 非 VIP 会收到 403;可先确认 VIP 状态
curl -s -b cookies.txt -o /dev/null -w "%{http_code}\n" "https://wap.iniche.cn/app/123/download"

查看个人资料

查看用户主页信息。

  • 端点GET /user(查看自己)或 GET /user/<id>(查看他人)。
  • 权限:查看他人公开(无需登录);查看自己需登录。

user 字段含:id, nickname, group_name, score, level, checkin_count, subject_count, post_count, app_count, like_received_count, essence_count, is_permanent_vip, vip_expire_at, created_at 等(email 仅本人可见)。

# 查看他人资料(公开,无需登录)
curl -s "https://wap.iniche.cn/user/42" -H "AJAX: 1"

# 查看自己(需登录 cookie)
curl -s -b cookies.txt "https://wap.iniche.cn/user" -H "AJAX: 1"

每日签到

每日签到可得积分(北京时间 UTC+8 判重,每天一次)。

  • 查询是否已签GET /user/checkin{ "signed": true|false }
  • 执行签到POST /user/checkin
  • 权限:登录 + 会员(USER_checkin);需 CSRF。基于 date(created_at,'+8 hours') 判重。

响应:成功 { "signed": true, "message": "签到成功 +2积分" };已签 { "signed": true, "message": "今日已签到" }

今日签到榜(公开)GET /user/checkinlist[/<page>],返回整页,含今日签到用户列表(totallist)。

# 查询今日是否已签到
curl -s -b cookies.txt "https://wap.iniche.cn/user/checkin" -H "AJAX: 1"

# 执行签到(需先取 CSRF 令牌,见「认证与 CSRF」)
curl -s -b cookies.txt -c cookies.txt -X POST "https://wap.iniche.cn/user/checkin" \
  -H "X-CSRF-Token: $TOKEN" -H "AJAX: 1"

资源 URL 拼接(截图 / 图标 / 头像)

所有图片资源落在 /data/disk/image/<userId>/…,由 nginx 按 Accept 头自动选择 webp / jpg(URL 无需扩展名)。下面给出客户端拼接公式,BASEhttps://wap.iniche.cn

资源URL 公式说明
应用图标/image/<user_id>/icon_<app_id>无扩展名;无图标回退 /image/default_app_icon.svg
应用截图/image/<user_id>/<hash1>来自 screenshots[].user_id + screenshots[].hash1
用户头像/avatar/<user_id>无扩展名;无头像回退 /default.webp
帖子附件 / 图片/image/<user_id>/<hash1>与截图同一条 /image/ 规则
缩略图(240 宽)/thumb/<user_id>/<hash1>自动 resize,适合列表展示
安装包下载/download/<user_id>/<hash1>.<ext>ext 取 app.ext;需 VIP 登录
BASE = "https://wap.iniche.cn"

# 应用图标:用 app.user_id + app.id
icon_url   = BASE + "/image/" + app.user_id + "/icon_" + app.id

# 应用截图:遍历 app 详情的 screenshots[],用每条的 user_id + hash1
shot_url   = BASE + "/image/" + s.user_id + "/" + s.hash1      # s = screenshots[i]

# 用户头像:用 user.id
avatar_url = BASE + "/avatar/" + user.id

# 缩略图(列表更省流量)
thumb_url  = BASE + "/thumb/" + s.user_id + "/" + s.hash1

# 安装包:用 app.user_id + app.hash1 + app.ext(需 VIP 登录后下载)
dl_url     = BASE + "/download/" + app.user_id + "/" + app.hash1 + "." + app.ext