Judge0 1.13.1 配置参数详解
逐项拆解 Judge0 1.13.1 的 judge0.conf 全部配置项:数据库与 Redis 连接、RAILS_MAX_THREADS/RAILS_SERVER_PROCESSES 空值强转崩溃、COUNTRIES 与 ALLOW_ORIGINS、AUTHN_HEADER 与 AUTHN_TOKEN、INTERVAL 队列轮询、CPU/WALL/MEMORY/STACK 限制与 MAX_PROCESSES、MAX_FILE_SIZE、ENABLE_WAIT_RESULT 同步开关、CALLBACKS_ENABLED 与回调参数、MAINTENANCE_MODE 及其批量提交绕过与中文消息 500 缺陷;附生产配置模板与 7 类实测问题。
Judge0 1.13.1 配置参数详解
目标:逐项拆解 Judge0 1.13.1
judge0.conf的全部配置项,给出默认值、生效范围(服务端 / 消费者 / 数据库客户端)与本地实测行为。文中的开关实测在 8142 实例(与 8141 基线实例共用同一份代码与数据库,仅环境变量不同)上完成,涉及语言运行时的用例在装有完整运行时的 8138 实例上执行。
一、环境信息
| 项 | 值 |
|---|---|
| Judge0 版本 | 1.13.1 |
| 配置文件 | /opt/judge0/judge0.conf(被 systemd 以 EnvironmentFile 加载) |
| 基线实例 | 8141,除连接信息外全部保持仓库默认值 |
| 开关实验实例 | 8142,同代码同库,仅覆盖待验证的环境变量 |
| 语义用例实例 | 8138,装有完整语言运行时(Python 3.8.1 / C++ GCC 9.2.0) |
| 数据库 | PostgreSQL 14.24,judge0 库 |
| 队列 | Redis 6.0.16,队列键 resque:queue:1.13.1 |
二、前置条件
- 已按 Ubuntu 安装篇完成服务端与消费者的部署,
/about返回1.13.1; - 有一份可用的
judge0.conf,且SECRET_KEY_BASE已持久化; - 能重启服务进程(多数开关在启动时读取,运行时修改无效)。
三、参数查看与修改方式
3.1 配置文件是「环境变量清单」
judge0.conf 并不是 YAML/INI,而是一份可以被 shell source 的键值清单。应用通过 app/helpers/config.rb 读取 ENV,因此:
- 配置项的唯一生效入口是环境变量(systemd
EnvironmentFile、shellexport、进程管理器的环境注入等价); - 修改
.conf后必须重启对应进程,Puma 与 Resque 都是启动时求值; - 注释里标注的
Default:是「空值时会回落到什么」,而回落逻辑写在代码里,见 3.2。
3.2 空值回落:两套不同的实现
app/helpers/config.rb 对几乎所有数值/布尔项都用了 .presence || 兜底:
CPU_TIME_LIMIT = (ENV["CPU_TIME_LIMIT"].presence || 5).to_f
MAX_QUEUE_SIZE = (ENV["MAX_QUEUE_SIZE"].presence || 100).to_i
ENABLE_CALLBACKS = ENV["ENABLE_CALLBACKS"] != "false"
但有几处直接强转,空字符串会立刻抛异常:
# config/puma.rb
threads_count = Integer(ENV['RAILS_MAX_THREADS'])
process_count = Integer(ENV['RAILS_SERVER_PROCESSES'])
# config/initializers/resque.rb
Resque.redis = Redis.new(port: ENV["REDIS_PORT"], password: ENV["REDIS_PASSWORD"])
# config/secrets.yml
authn_header: <%= ENV["AUTHN_HEADER"] %>
authn_token: <%= ENV["AUTHN_TOKEN"].to_s.strip %>
实测后果见第七章的第 7.1–7.4 条。这也是「打包发行版里留空没事、裸机部署留空出事」的根本原因:打包路径的启动脚本会先补默认值再 source。
3.3 运行期可查的配置快照
/config_info 返回服务端实际生效的开关与限制(不含密码类):
$ curl -s http://127.0.0.1:8138/config_info | python3 -m json.tool | head -20
{
"maintenance_mode": false,
"enable_wait_result": true,
"enable_compiler_options": true,
"allowed_languages_for_compile_options": [],
"enable_command_line_arguments": true,
"enable_submission_delete": false,
"enable_callbacks": true,
"callbacks_max_tries": 3,
"callbacks_timeout": 5.0,
"enable_additional_files": true,
"max_queue_size": 100,
"cpu_time_limit": 5.0,
"max_cpu_time_limit": 15.0,
"cpu_extra_time": 1.0,
"max_cpu_extra_time": 5.0,
"wall_time_limit": 10.0
}
这是核对「配置到底有没有生效」最快的手段,比翻日志可靠。
四、参数总览
4.1 服务端行为开关
| 参数 | 默认值 | 作用域 | 说明 |
|---|---|---|---|
MAINTENANCE_MODE | false | 服务端 | 只拦截 POST /submissions 与 DELETE /submissions/:token |
MAINTENANCE_MESSAGE | Judge0 is currently in maintenance. | 服务端 | 维护期返回的 error 文本 |
ENABLE_WAIT_RESULT | true | 服务端 | 关闭后 wait=true 返回 400 |
ENABLE_COMPILER_OPTIONS | true | 服务端 | 是否允许提交自定义编译选项 |
ALLOWED_LANGUAGES_FOR_COMPILER_OPTIONS | 空(全部) | 服务端 | 白名单语言名,空格分隔 |
ENABLE_COMMAND_LINE_ARGUMENTS | true | 服务端 | 是否允许提交命令行参数 |
ENABLE_SUBMISSION_DELETE | false | 服务端 | 是否允许 DELETE /submissions/:token |
ENABLE_BATCHED_SUBMISSIONS | true | 服务端 | 是否开放 /submissions/batch |
MAX_SUBMISSION_BATCH_SIZE | 20 | 服务端 | 单次批量提交/查询的上限 |
ENABLE_CALLBACKS | true | 服务端 + 消费者 | 是否发送回调 |
CALLBACKS_MAX_TRIES | 3 | 消费者 | 回调失败重试次数 |
CALLBACKS_TIMEOUT | 5 | 消费者 | 单次回调超时(秒) |
ENABLE_ADDITIONAL_FILES | true | 服务端 | 是否允许 additional_files |
SUBMISSION_CACHE_DURATION | 1 | 服务端 | 只缓存按 token 的查询结果,不做提交去重 |
USE_DOCS_AS_HOMEPAGE | false | 服务端 | 是否把文档页设为首页 |
JUDGE0_TELEMETRY_ENABLE | true | 服务端 | 遥测上报开关 |
RESTART_MAX_TRIES | 10 | 启动脚本 | 启动失败重试次数(仅打包启动脚本使用) |
4.2 访问控制
| 参数 | 默认值 | 作用域 | 说明 |
|---|---|---|---|
ALLOW_ORIGIN / DISALLOW_ORIGIN | 空 | 服务端 | CORS 白/黑名单,空格分隔 |
ALLOW_IP / DISALLOW_IP | 空 | 服务端 | 来源 IP 白/黑名单,按 request.remote_ip 判断 |
AUTHN_HEADER | X-Auth-Token(仅打包脚本补) | 服务端 | 鉴权头名,见 7.2 |
AUTHN_TOKEN | 空(关闭鉴权) | 服务端 | 支持空格分隔多令牌 |
AUTHZ_HEADER | X-Auth-User(仅打包脚本补) | 服务端 | 授权头名 |
AUTHZ_TOKEN | 空(受保护接口全部 403) | 服务端 | 授权令牌,未配置时受保护接口不可用 |
4.3 队列与消费者
| 参数 | 默认值 | 作用域 | 说明 |
|---|---|---|---|
INTERVAL | 0.1 | 消费者 | 轮询间隔,空值会导致消费者静默退出 |
COUNT | 2*nproc | 消费者 | 并行消费者数量,仅打包启动脚本使用 |
MAX_QUEUE_SIZE | 100 | 服务端 | 队列上限,超出返回 503 queue is full |
QUEUE / JUDGE0_VERSION | 空 / 版本号 | 消费者 + 服务端 | Resque 队列名,同时是 /about 的版本字段 |
4.4 执行限制
| 参数 | 默认值 | 上限项默认值 | 实测说明 |
|---|---|---|---|
CPU_TIME_LIMIT | 5 | MAX_CPU_TIME_LIMIT=15 | 单次提交 CPU 时间(秒,可小数) |
CPU_EXTRA_TIME | 1 | MAX_CPU_EXTRA_TIME=5 | 超时后额外宽限,用于报告真实耗时 |
WALL_TIME_LIMIT | 10 | MAX_WALL_TIME_LIMIT=20 | 墙钟时间,防睡眠程序 |
MEMORY_LIMIT | 128000(KB) | MAX_MEMORY_LIMIT=512000 | 地址空间/内存 cgroup 上限 |
STACK_LIMIT | 64000(KB) | MAX_STACK_LIMIT=128000 | 进程栈上限 |
MAX_PROCESSES_AND_OR_THREADS | 60 | MAX_MAX_PROCESSES_AND_OR_THREADS=120 | 依赖 cgroup 的进程数上限 |
ENABLE_PER_PROCESS_AND_THREAD_TIME_LIMIT | false | ALLOW_...=true | 计时按进程/线程而非总量 |
ENABLE_PER_PROCESS_AND_THREAD_MEMORY_LIMIT | false | ALLOW_...=true | 内存按进程/线程而非总量 |
MAX_FILE_SIZE | 1024(KB) | MAX_MAX_FILE_SIZE=4096 | 可写文件大小上限 |
NUMBER_OF_RUNS | 1 | MAX_NUMBER_OF_RUNS=20 | 重复运行取平均 |
REDIRECT_STDERR_TO_STDOUT | false | — | 把 stderr 并入 stdout |
MAX_EXTRACT_SIZE | 10240(KB) | — | 附加文件解压总量上限 |
ALLOW_ENABLE_NETWORK | true | — | 是否允许提交方申请联网 |
ENABLE_NETWORK | false | — | 默认是否允许程序联网 |
4.5 连接与凭证
| 参数 | 默认值 | 作用域 | 说明 |
|---|---|---|---|
REDIS_HOST / REDIS_PORT | localhost / 6379 | 服务端 + 消费者 | 端口空值会触发 Float("") 异常 |
REDIS_PASSWORD | 无默认值(必填) | 服务端 + 消费者 | 直接传入 Redis.new |
POSTGRES_HOST / POSTGRES_PORT | localhost / 5432 | 服务端 + 消费者 | database.yml 直接切分该值 |
POSTGRES_DB / POSTGRES_USER / POSTGRES_PASSWORD | postgres / postgres / 必填 | 服务端 + 消费者 | 生产模式生效 |
4.6 Rails 与服务进程
| 参数 | 默认值 | 作用域 | 说明 |
|---|---|---|---|
RAILS_ENV | production | 全部 | 决定 database.yml 读取哪一段 |
RAILS_MAX_THREADS | nproc | 服务端 | Puma 线程数 = 数据库连接池大小 |
RAILS_SERVER_PROCESSES | 2 | 服务端 | Puma cluster 进程数 |
SECRET_KEY_BASE | 随机生成(打包脚本) | 服务端 | 裸机部署必须持久化,否则重启后会话/缓存签名变化 |
PORT | 2358 | 服务端 | 不在 judge0.conf 中,只能通过环境变量或 -p 传入 |
五、核心参数分类详解
5.1 维护模式与 wait 语义
维护模式只覆盖两个动作。源码里写死了白名单:
# app/controllers/submissions_controller.rb:3
before_action :check_maintenance, only: [:create, :destroy]
实测(MAINTENANCE_MODE=true,消息为 ASCII):
$ curl -s -w " [%{http_code}]" -X POST http://127.0.0.1:8142/submissions \
-H "Content-Type: application/json" \
-d '{"source_code":"print(1)","language_id":71}'
{"error":"Judge0 maintenance window, try later"} [503]
但批量提交不受拦截:
$ curl -s -w " [%{http_code}]" -X POST http://127.0.0.1:8142/submissions/batch \
-H "Content-Type: application/json" \
-d '{"submissions":[{"source_code":"print(2)","language_id":71}]}'
[{"token":"3659b9eb-54e1-4980-b872-de0dcd37fa15"}] [201]
GET /about 在维护期仍返回 200,可作为健康检查用。另一处坑:MAINTENANCE_MESSAGE 写中文时,check_maintenance 渲染会抛编码异常,POST /submissions 返回 500 而不是 503:
FATAL -- : Encoding::UndefinedConversionError ("\xE7" from ASCII-8BIT to UTF-8):
FATAL -- : app/controllers/sessions_controller.rb:35:in `check_maintenance'
结论:维护消息保持 ASCII,否则维护期会变成「500 而不是可读的 503」。
ENABLE_WAIT_RESULT=false 关闭同步等待:
$ curl -s -w " [%{http_code}]" -X POST "http://127.0.0.1:8142/submissions?wait=true" ...
{"error":"wait not allowed"} [400]
不带 wait 的提交仍返回 201 与 token。
💡 技术拓展:
wait=true时IsolateJob在 API 进程内联执行(perform_now),不走队列,因此不受MAX_QUEUE_SIZE约束,也不消耗消费者。这让「同步提交」在流量高峰时会直接占满 Puma 线程——RAILS_MAX_THREADS实际上成了同步提交的并发上限。需要抗压时应关闭ENABLE_WAIT_RESULT,全部走异步。
5.2 队列上限与消费者节奏
MAX_QUEUE_SIZE 的判定发生在创建提交时,统计口径是「当前队列长度 + 本次提交数」:
if Resque.size(ENV["JUDGE0_VERSION"]) + number_of_submissions > Config::MAX_QUEUE_SIZE
把 MAX_QUEUE_SIZE 调成 2 并停掉消费者后连续提交四次:
submit1: 201 {"token":"20c6260c-076b-49cd-9f5e-a15a66b768c9"}
submit2: 201 {"token":"faaa073d-d23b-4875-9a8e-09de16f096f0"}
submit3: 503 {"error":"queue is full"}
submit4: 503 {"error":"queue is full"}
此时队列键的实际长度:
$ redis-cli -a judge0_redis_pwd_2026 keys "resque:queue:*"
resque:queue:1.13.1
$ redis-cli -a judge0_redis_pwd_2026 llen "resque:queue:1.13.1"
2
注意队列键带 resque:queue: 前缀,直接 llen 1.13.1 会得到 0,误判为「队列空但被拒绝」。
INTERVAL 决定消费者轮询间隔,默认 0.1 秒。它必须显式设值:空值时 Resque::Worker#work 的 Float(interval) 抛异常,被 rescue Exception 吞掉,进程以 0 退出(见 7.4)。
COUNT 只在打包启动脚本里生效(rake resque:workers),systemd 直接跑 resque:work 时不起作用,并行度由单元实例数决定。
5.3 鉴权与授权
AUTHN_TOKEN 配置后,所有接口(含 GET /about)都需要携带令牌;令牌可放在请求头或查询参数:
$ curl -s -w " [%{http_code}]" http://127.0.0.1:8142/about
[401]
$ curl -s -w " [%{http_code}]" -H "X-Auth-Token: test_token_2026" http://127.0.0.1:8142/about
{"version":"1.13.1","homepage":null,"source_code":null,"maintainer":null} [200]
$ curl -s -w " [%{http_code}]" "http://127.0.0.1:8142/about?X-Auth-Token=test_token_2026"
{"version":"1.13.1","homepage":null,"source_code":null,"maintainer":null} [200]
401 的响应体为空,排查时不要去找 JSON 错误信息。
AUTHN_HEADER 必须在裸机部署时显式写 X-Auth-Token:config/secrets.yml 直接取 ENV["AUTHN_HEADER"],没有默认值。实测只配 AUTHN_TOKEN 而未配 AUTHN_HEADER 时,带正确令牌也返回 401——因为头名是空串,永远匹配不到。
AUTHZ_* 用于受保护的管理类接口(如删除提交),AUTHZ_TOKEN 为空时这些接口直接 403,与 ENABLE_SUBMISSION_DELETE 是两个独立的闸门。
5.4 提交缓存:只缓存查询,不去重
SUBMISSION_CACHE_DURATION 的注释容易被误读为「提交去重」。实际代码只包住了 show:
# app/controllers/submissions_controller.rb:59 (show)
render json: Rails.cache.fetch("#{token}", expires_in: Config::SUBMISSION_CACHE_DURATION, ... ) {
Submission.find_by!(token: token)
}
实测同一份源码连续提交两次,token 不同:
t1=9d26ea41-b28e-45a4-a7e3-dabc5dde70b1
t2=61a938c5-9b38-45b1-8047-de3faf49637e
DIFFERENT
所以它的作用是「GET /submissions/{token} 的结果在 N 秒内走缓存」,降低高频轮询对数据库的压力。设为 0 可关闭缓存;批量查询接口不受该缓存影响(源码注释已说明)。
5.5 执行限制的级联关系
每个提交的最终限制由「全局默认值 × 提交级覆盖 × 全局上限」三者决定:提交里的 cpu_time_limit、memory_limit 等字段可以覆盖默认值,但不能超过 MAX_*。实测超上限直接被模型校验拦下:
$ curl -s -w " [%{http_code}]" -X POST http://127.0.0.1:8138/submissions \
-H "Content-Type: application/json" \
-d '{"source_code":"print(1)","language_id":71,"memory_limit":600000}'
{"memory_limit":["must be less than or equal to 512000"]} [422]
返回的是 Rails 模型校验错误(422),不是执行阶段的错误码,这类问题不会进入队列。
时间限制的实际落点可用死循环验证(cpu_time_limit=1):
{
"stdout": null,
"time": "0.002",
"memory": 3268,
"message": "Time limit exceeded (wall clock)",
"status": {"id": 5, "description": "Time Limit Exceeded"}
}
message 明确标注是墙钟超限而不是 CPU 超限,说明孤立执行环境中 CPU 时间几乎没被消耗(进程被调度器挂起),真正兜底的是 WALL_TIME_LIMIT。
内存限制的表现为「程序自己报错」而不是「状态码 6/12 类」:
{
"stdout": null,
"memory": 7836,
"stderr": "Traceback (most recent call last):\n File \"script.py\", line 1, in <module>\n a='x'*(300*1024*1024)\nMemoryError\n",
"message": "Exited with error status 1",
"status": {"id": 11, "description": "Runtime Error (NZEC)"}
}
memory_limit=64000 时 Python 在分配阶段收到 MemoryError 自行退出,最终状态是 NZEC(11)而非独立的 MLE 状态(Judge0 没有 MLE 状态码)。监控上不能靠状态码区分「内存不足」与「普通运行时错误」。
5.6 回调参数
ENABLE_CALLBACKS、CALLBACKS_MAX_TRIES、CALLBACKS_TIMEOUT 由消费者侧执行。实测回调请求使用 PUT 而不是 POST,请求体是 base64_encoded=true 的完整提交 JSON:
METHOD=PUT PATH=/cb
{"stdout":"NTYK\n","time":"0.009","memory":7992,"stderr":null,"token":"823ac49f-497e-4dcb-bbc8-07a24514d6f7","compile_output":null,"message":null,"status":{"id":3,"description":"Accepted"}}
接收端只实现 do_POST 时会收到 501,重试 CALLBACKS_MAX_TRIES 次后静默放弃——日志里没有任何记录,这是回调「看起来没触发」的最常见原因。
5.7 批量与选项开关
MAX_SUBMISSION_BATCH_SIZE 的超限校验发生在控制器入口:
$ # 提交 21 条
400 {"error":"number of submissions in a batch should be less than or equal to 20"}
ENABLE_BATCHED_SUBMISSIONS=false 时 /submissions/batch 直接不可用;ENABLE_COMPILER_OPTIONS / ALLOWED_LANGUAGES_FOR_COMPILER_OPTIONS 控制编译选项白名单,ALLOWED_... 为空表示不限制语言。ENABLE_COMMAND_LINE_ARGUMENTS=false 后提交里的 command_line_arguments 会被忽略而不是报错。
六、生产配置模板
6.1 面向 8 核 / 16GB / 纯异步的模板
适用场景:中等并发的在线评测,客户端全部走异步 + 轮询或回调。
# 连接
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=<强密码>
POSTGRES_HOST=localhost
POSTGRES_PORT=5432
POSTGRES_DB=judge0
POSTGRES_USER=judge0
POSTGRES_PASSWORD=<强密码>
# Rails / 服务进程
RAILS_ENV=production
RAILS_MAX_THREADS=8
RAILS_SERVER_PROCESSES=2
SECRET_KEY_BASE=<64字节以上随机串,持久化>
# 消费者
INTERVAL=0.1
# 队列
MAX_QUEUE_SIZE=200
# 执行限制(评测口径)
CPU_TIME_LIMIT=5
MAX_CPU_TIME_LIMIT=10
WALL_TIME_LIMIT=10
MAX_WALL_TIME_LIMIT=15
MEMORY_LIMIT=256000
MAX_MEMORY_LIMIT=512000
STACK_LIMIT=64000
MAX_PROCESSES_AND_OR_THREADS=60
MAX_FILE_SIZE=1024
# 接口开关
ENABLE_WAIT_RESULT=false
ENABLE_SUBMISSION_DELETE=false
ENABLE_CALLBACKS=true
CALLBACKS_MAX_TRIES=3
CALLBACKS_TIMEOUT=5
MAX_SUBMISSION_BATCH_SIZE=20
SUBMISSION_CACHE_DURATION=1
# 访问控制
AUTHN_HEADER=X-Auth-Token
AUTHN_TOKEN=<令牌>
AUTHZ_HEADER=X-Auth-User
AUTHZ_TOKEN=<令牌>
ALLOW_ORIGIN=https://judge.example.com
# 维护
MAINTENANCE_MODE=false
MAINTENANCE_MESSAGE=Judge0 maintenance in progress, please retry later.
容量估算:RAILS_SERVER_PROCESSES × RAILS_MAX_THREADS = 16 个并发请求线程,数据库连接池按 8/进程配置;消费者按 nproc/2 个 resque:work 实例即可覆盖 8 核。
6.2 面向 16 核 / 32GB / 允许同步等待的模板
在 6.1 基础上调整三处:RAILS_MAX_THREADS=12、RAILS_SERVER_PROCESSES=2、ENABLE_WAIT_RESULT=true。同步提交会占用 API 线程直至执行完成,因此 WALL_TIME_LIMIT 不宜超过 15 秒,否则单次请求可能拖到 20 秒以上。
七、常见问题
7.1 修改 judge0.conf 后不生效
配置文件只在进程启动时被读取。Puma 与 Resque 都不会热加载,需要重启对应服务;/config_info 是确认是否生效的最快方式。
7.2 配置了 AUTHN_TOKEN 但所有请求 401
AUTHN_HEADER 未设值。config/secrets.yml 直接取 ENV["AUTHN_HEADER"],裸机部署必须显式写成 X-Auth-Token,否则头名为空串,任何令牌都匹配不到。
7.3 Puma 启动失败 invalid value for Integer(): ""
config/puma.rb:1:in `Integer': invalid value for Integer(): "" (ArgumentError)
RAILS_MAX_THREADS 或 RAILS_SERVER_PROCESSES 为空。Config 模块对这两项没有兜底,必须在配置文件里写值。
7.4 消费者启动 1 秒即退出
INTERVAL 为空导致 Float("") 异常,被 rescue Exception 吞掉后正常退出(退出码 0),日志无任何报错。补上 INTERVAL=0.1 即可。
7.5 维护期返回 500 而不是 503
MAINTENANCE_MESSAGE 含中文/非 ASCII 字符,check_maintenance 渲染时抛 Encoding::UndefinedConversionError。改用 ASCII 文案。
7.6 队列明明是空却被拒绝
检查是否漏了 Resque 前缀,正确键是 resque:queue:<JUDGE0_VERSION>;同时注意 MAX_QUEUE_SIZE 的判定包含「本次批量提交的条数」,一次提交 20 条会直接吃掉 20 个配额。
7.7 AUTHZ_TOKEN 为空时受保护接口一律 403
这是设计行为:授权未配置时受保护接口不可用。需要删除提交等能力时必须同时配置 AUTHZ_TOKEN 与 ENABLE_SUBMISSION_DELETE=true。
八、参考链接
judge0.conf原文与逐项注释:https://github.com/judge0/judge0/blob/master/judge0.conf- 配置读取实现:https://github.com/judge0/judge0/blob/master/app/helpers/config.rb
- 官方配置说明:https://github.com/judge0/judge0/blob/master/docs/api/system_and_configuration/configuration_info.md
- 站内:《Judge0 1.13.1 介绍与选型指南》
- 站内:《Ubuntu 22.04 安装 Judge0 1.13.1 指南》
- 站内:《Judge0 1.13.1 单机四服务栈部署指南》
- 站内:《Judge0 1.13.1 REST API 使用详解》