Repository navigation
Course Community
| 项 | 值 |
|---|---|
| 平台 | course.sjtu.plus |
| 认证 | 用户 API Key(Authorization: Bearer) |
| 数据方向 | 只读 + 写(点评、投票、关注、选课记录) |
| 难度 | 低 |
| 最后验证 | 2026-10-26 |
| 证据等级 | A(站点自有文档 + 关键端点实测) |
选课社区是学生自建的课程点评站,基于 SJTU-jCourse/next。它维护了一份给 Agent 用的 API 参考,接口形态比多数校园私有接口稳定;但站点和文档都来自学生项目,不是学校的教学系统。
- 可获取:课程、教师、评分分布、点评、本人选课和关注状态(实测);积分记录、站点公告按文档列出,未看到实际数据。
- 前置:用户自己在站点生成的 API Key。API Key 以本人身份工作,能读也能写。
- 注意:点评里的成绩是用户自填的,不是教学信息网的官方成绩;
score与rating是两个字段。 - 没有匿名读接口:不带 Key 的请求一律 401,连公告和筛选接口也一样。
[实测 2026-10-26]
| 对象 | 内容 | 备注 |
|---|---|---|
| 账号 |
id、username、email、role
|
/api/auth/me 探活 |
| 课程 |
id、code、name、credit、department、language、target_years、categories、main_teacher
|
列表项 |
| 评分 |
count、avg、score、distribution(5 元素,1–5 星计数) |
avg 是均分;score 是站点算出的综合分,算法未公开;列表里的 distribution 实测恒为全 0(抽查 6 门课),真实分布只在详情页
|
| 课程详情 |
last_semester、offered_courses、same_code_courses、same_teacher_courses、notification_level、moderator_remark、my_enrollments、my_review
|
抽查 12 门课都没有文档写的 teacher_group;my_enrollments/my_review 只在有数据时出现 |
| 点评 |
id、course_id、semester、score、rating、content、moderator_remark、vote、created_at、updated_at
|
score 是自由文本,不是成绩枚举;实测响应没有文档写的 course、user_id
|
| 教师 |
id、code、name、department、title
|
教师页可按评分排序课程 |
| 本人数据 | 选课记录、关注/忽略课程、本人点评;积分返回 {records, total}
|
需要 API Key |
| 公告 |
id、title、body、priority、created_at
|
字段来自 API 参考;两次实测都返回空数组,没有实际条目可核对 |
| 部分 | Base URL | 鉴权 | 用途 |
|---|---|---|---|
| 网页 | https://course.sjtu.plus/ |
邮箱 + 密码 / jAccount 同步 | 浏览、点评、生成 API Key |
| API | https://course.sjtu.plus/api |
用户 API Key 或浏览器会话 | 本页主体 |
| 扩展接口 | /api/ext/* |
系统 API Key(管理员创建) | 站点间集成,个人用不到 |
Bearer API Key 的校验先于会话校验;带有效 Key 时,写操作跳过 CSRF。[官方] JCourse API Reference
- 站点账号是
用户名@sjtu.edu.cn形式的交大邮箱:前端把用户名直接拼上@sjtu.edu.cn,该域名来自站点配置项auth.email_domain。它和 jAccount 是两套账号。[代码] - 在站点的 API Key 管理页新建一个 Key,明文只显示一次。
- 把 Key 存进本机密钥存储,不写进代码、日志或仓库。
对应接口是 GET/POST /api/api-key/(创建 body {"name":"agent"})与 DELETE /api/api-key/{id}。[官方]
GET /user/settings 在 2026-10-26 的实测中不可用:不带斜杠返回 404,带斜杠返回 301 再落到 404。同轮试了 /user/setting、/settings、/user、/user/profile 也都是 404,带 Key 也一样,说明这组路径在当前部署不存在。[实测 2026-10-26]
GET https://course.sjtu.plus/api/auth/me
Authorization: Bearer <api_key>{"id":1,"username":"u1","email":"u1@example.edu","role":"user"}不带 Key 时,课程列表、筛选、点评、教师、公告、API Key 管理全部返回 401 {"error":"unauthorized"};站点不提供公开读接口。[实测 2026-10-26,未登录]
同一个 Key 可以关注课程、发点评、改点评、投票、改选课记录。只把它交给本人控制的工具,并且写操作前逐次确认目标。[官方]
Base:https://course.sjtu.plus/api
| 接口 | 关键参数 | 返回 |
|---|---|---|
GET /course/filter |
- |
credits、departments、categories、target_years、languages、semesters 及计数 |
GET /course/ |
q、department、language、categories、target_years、credit、has_review、order_by、ascend、page、page_size
|
课程分页,order_by 取 rating_score/rating_count/rating_avg
|
GET /course/hot |
period=week|month、limit
|
items 为 {course, score};热门度不是评分 |
GET /course/{id} |
路径 | 详情、授课教师、相关课程、本人状态 |
GET /course/{id}/review/filter |
路径 | 可选学期与评分 |
GET /course/{id}/review/trend |
路径 | [{semester, avg, count}] |
GET /teacher/ |
q、department、title、page、page_size
|
教师分页 |
GET /teacher/{id}、GET /teacher/{id}/course
|
路径 | 教师详情与其课程 |
| 接口 | 关键参数 | 返回 |
|---|---|---|
GET /course/{id}/review |
q、semester、rating、order_by=like_count|created_at、page、page_size
|
课程点评分页 |
GET /review |
q、semester、rating、order_by、page、page_size
|
全站点评;登录后排除已忽略课程 |
GET /review/{id} |
路径 | 单条点评 |
POST /review/ |
body:course_id、rating、content;可选 semester、score
|
写操作;敏感内容返回 400 |
PUT /review/{id}、DELETE /review/{id}
|
路径 + body | 写操作;一般是本人或管理员 |
POST /review/{id}/vote |
body:vote_type(1 赞、-1 踩、0 取消) |
写操作;有每日上限,超限 429 |
GET /user/{id}/review |
路径 + 分页 | 本人或管理员 |
| 接口 | 关键参数 | 返回 |
|---|---|---|
POST /course/{id}/notification |
body:{"level":0|1|2}(普通、关注、忽略) |
写操作 |
GET /course/followed、GET /course/ignored
|
分页 | 关注 / 忽略列表 |
GET /review/followed |
分页 | 关注课程的点评 |
GET /course/enrolled |
- | 本人选课记录 |
POST /course/{id}/enrollment、DELETE /course/enrollment/{id}
|
body:{"semester"}
|
写操作 |
GET /user/{id}/point |
分页 | 积分与积分记录 |
GET /announcement/ |
- | 站点公告 |
文档还列出 GET/PUT /user/settings;2026-10-26 实测六个路径全部 404,已不列入上表。[实测 2026-10-26]
写操作端点来自官方文档,本页没有执行;POST /review/ 一类请求在提交前要逐次确认目标、内容和影响。[官方]
GET /course/enrollment-sync/start?semester=... 是浏览器 OAuth 式的 jAccount 同步入口,回调在 /course/enrollment-sync/callback;不适合在 Agent 里自动跑。[官方]
分页统一为:
{"items": [], "total": 0, "page": 1, "page_size": 20}- 默认
page=1&page_size=20。[官方] - 数组型过滤条件重复同一个 key:
?categories=CORE&categories=ELECTIVE&target_years=2026。 - 布尔参数用
0/1,前端客户端按这个习惯发请求。
课程列表项:
{
"id": 123,
"code": "CS101",
"name": "数据结构",
"credit": 3,
"department": "计算机学院",
"language": "zh",
"target_years": ["2026"],
"categories": ["core"],
"last_semester": "2025-2026-2",
"main_teacher": {"id": 10, "name": "教师"},
"rating": {"count": 12, "avg": 4.3, "score": 4.1, "distribution": [0, 0, 0, 0, 0]}
}列表项实测要点(2026-10-26):last_semester 也在列表里;rating.distribution 在列表里恒为 [0,0,0,0,0],同一门课的 GET /course/{id} 却返回真实分布(如 [0,0,1,3,197],count 同为 201)。抽查 6 门课(count 66–201)全部如此,要做评分分布必须取详情。[实测 2026-10-26]
点评对象:
{
"id": 55,
"course_id": 123,
"semester": "2025-2026-1",
"score": "A",
"rating": 5,
"content": "...",
"moderator_remark": "",
"vote": {"like_count": 3, "dislike_count": 0, "my_vote": 1},
"created_at": "2026-01-01T00:00:00Z",
"updated_at": "2026-01-01T00:00:00Z"
}错误统一是 {"error": "..."},例如未登录:
{"error":"unauthorized"}| 状态码 | 含义 |
|---|---|
| 400 | 参数或 body 不合法;点评内容触发敏感词;投票值或关注级别不合法 |
| 401 | 未登录、Key 无效或会话过期 |
| 403 | 无权限、CSRF 失败、账号被限制 |
| 404 | 课程、点评、教师、用户或 Key 不存在 |
| 409 | 重复操作或积分不足 |
| 429 | 限流、验证过于频繁、每日投票上限 |
[官方]
-
rating与score:rating是星级(1–5),score是点评者填的成绩。做课程推荐只用rating,把score当参考。rating.score是站点综合分,算法未公开,不要自造解释。 -
样本量:
rating.count可能是个位数;少于 5 条时不要给「好课/水课」结论,也不要在排序里让低样本课程挤到前面。 -
热门度:
/course/hot的score是活跃度得分,不是评分。period只有week/month。 -
点评时点:点评带
semester和created_at;教学安排和给分风格会随学期变化,展示时带上学期。 -
自填成绩:
score是用户主观填写的,不代表教学信息网记录,也不能用来推断某门课的真实给分。 -
内容审核:
moderator_remark非空表示被处理过;引用点评时保留原文链接。 -
评分分布:列表接口的
distribution全 0,只有详情接口有真实值;把「有分布」当成列表能力会得到全零图。[实测 2026-10-26] -
score不是枚举:120 条点评样本里出现空字符串(62 条)、A、90、95、4.0、4.3等混合取值,字母、百分制、GPA 制都有;不要按固定格式解析,做统计前先归类。[实测 2026-10-26]
-
401 / 403:Key 被删除或输入错误;先
GET /auth/me。 - 写操作返回 400:点评内容触发敏感词;不要反复重试同一段文字。
- 429:投票有每日上限,也可能触发站点限流;退避,不要绕过。
- CSRF:只有浏览器会话需要;用 API Key 时不带 CSRF 也能写,这更要求 Key 保密。
- Key 明文只出现一次:创建后立刻保存,不要指望再查一次。
- 忽略的课程从全站点评里消失:这是预期行为,不是接口漏数据。
-
page_size上限:文档给出默认 20,没写死最大值;别一次拉全站。 - 匿名请求全是 401:这是站点的默认行为,不是 Key 配错;先确认 Key 是否已经带上。
-
/user/settings带 Key 也 404:试过六个路径都不通;文档写的路径在当前部署不存在。[实测 2026-10-26] -
详情里没有
teacher_group:文档列为详情字段,抽查 12 门课都没有;按main_teacher和offered_courses取教师与学期。[实测 2026-10-26] -
my_review/my_enrollments会缺席:只在有数据时出现,缺字段不等于接口失败。[实测 2026-10-26]
const API = 'https://course.sjtu.plus/api';
async function searchCourses(key: string, keyword: string) {
const query = new URLSearchParams({ q: keyword, page: '1', page_size: '20' });
const response = await fetch(`${API}/course/?${query}`, {
headers: { Authorization: `Bearer ${key}`, Accept: 'application/json' },
});
if (response.status === 401) throw new Error('选课社区 API Key 已失效');
if (!response.ok) throw new Error(`选课社区 HTTP ${response.status}`);
const payload = await response.json();
if (!Array.isArray(payload?.items)) throw new Error('课程列表结构已变化');
return payload.items;
}
async function courseReviews(key: string, courseId: number) {
const query = new URLSearchParams({
order_by: 'like_count',
page: '1',
page_size: '20',
});
const response = await fetch(`${API}/course/${courseId}/review?${query}`, {
headers: { Authorization: `Bearer ${key}`, Accept: 'application/json' },
});
if (response.status === 401) throw new Error('选课社区 API Key 已失效');
if (!response.ok) throw new Error(`选课社区 HTTP ${response.status}`);
const payload = await response.json();
return Array.isArray(payload?.items) ? payload.items : [];
}- 不要批量发点评、刷票或替他人发点评;这些是社区内容,不是个人数据。
- 不要在日志、终端输出或错误信息里打印 API Key。
- 不要把社区评分当成学校对课程质量的评价。
- 不要绕过每日投票上限、敏感词审核或站点限流。
- API Key 可用、
/api/auth/me与课程搜索返回 200:[实测 2026-10-25,本人 Key,只读] - 端点、参数、字段、分页、错误码:
[官方]JCourse API Reference、SJTU-jCourse/next - 带 Key 实测:
/auth/me、课程列表(total:100)、筛选、热门、教师、课程详情、点评(total:201)、趋势、点评筛选均 200;/course/enrolled、/announcement/返回空数组:[实测 2026-10-26,本人 API Key,只读];记录未入库。 - 积分接口返回
{records, total}(本人total: 0);120 条点评样本的score混合空串、字母、百分制与 GPA:[实测 2026-10-26,本人 API Key,只读] - 未登录时已试接口 401
{"error":"unauthorized"}、/user/settings返回 404、站点首页可访问:[实测 2026-10-26,未登录,只读探测] - 服务入口:
[官方]选课社区
- 2026-10-25:首版。按项目内 API 参考整理端点,只读部分已实测,写操作未执行。
- 2026-10-26:补匿名探测结果与错误响应表;确认积分字段、公告为空、
teacher_group12 门课均无、score混合取值、注册邮箱域来自auth.email_domain。 - 2026-10-26:带 Key 复测关键端点,证据等级 B → A;更正三处文档与实现不符(列表
distribution全 0、无teacher_group、/user/settings不存在)。
本 Wiki 记录的是开发实践,不是学校官方承诺。每个结论都标注证据与日期;校园平台会调整字段、权限和登录方式,动手前请按页面里的「最后验证」复核。发现过期内容请提 Issue 或直接改。