如何通过Java调用Jupyter Server REST API成功上传本地Jupyter笔记本内容
解决Java调用Jupyter Server API上传笔记本内容为空的问题
我之前也碰到过类似的坑,核心是对Jupyter Server API的字段格式要求理解不到位,加上Java处理JSON时的小细节出错导致的。下面给你拆解问题和具体的解决方案:
问题根源分析
你遇到的空文件问题,主要有这几个关键原因:
content字段格式错误:你把JSON字符串转成JSONObject再嵌套,或者传递了字符串格式的JSON,而Jupyter期望的是笔记本原始JSON结构直接作为content的值(也就是ipynb文件解析后的JSON对象)。- 字段类型不匹配:比如
writable应该是布尔值true,而不是字符串"True";mimetype不需要设为"None",要么留空要么设为"application/json",字符串"None"会被服务器识别为无效值。 - 请求头缺失或错误:没有设置
Content-Type: application/json,导致服务器无法正确解析请求体。
具体Java实现方案
我用OkHttp(Java常用的HTTP客户端)和org.json库来实现,步骤清晰且容易调试:
1. 添加依赖(Maven)
首先在pom.xml里加入需要的依赖:
<dependency> <groupId>com.squareup.okhttp3</groupId> <artifactId>okhttp</artifactId> <version>4.12.0</version> </dependency> <dependency> <groupId>org.json</groupId> <artifactId>json</artifactId> <version>20240303</version> </dependency>
2. 完整上传代码
import okhttp3.MediaType; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; import org.json.JSONObject; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; public class JupyterNotebookUploader { public static void main(String[] args) throws IOException { // 配置你的Jupyter Server信息 String jupyterBaseUrl = "http://localhost:8888"; // 替换成你的服务器地址 String targetNotebookName = "a.ipynb"; String localNotebookPath = "/Users/you/path/to/local/a.ipynb"; // 本地文件路径 String jupyterAuthToken = "your-token-here"; // 如果服务器开启认证,填你的token // 第一步:读取本地ipynb文件,直接解析为JSONObject String rawNotebookContent = new String(Files.readAllBytes(Paths.get(localNotebookPath))); JSONObject notebookJson = new JSONObject(rawNotebookContent); // 第二步:构造符合API要求的请求体 JSONObject requestBody = new JSONObject(); requestBody.put("name", targetNotebookName); requestBody.put("path", ""); // 上传到服务器根目录,可根据需要修改路径 requestBody.put("type", "notebook"); requestBody.put("format", "json"); requestBody.put("content", notebookJson); // 直接放入解析后的笔记本JSON requestBody.put("writable", true); // 注意是布尔值,不是字符串 // 第三步:配置HTTP请求 OkHttpClient client = new OkHttpClient(); MediaType jsonMediaType = MediaType.get("application/json; charset=utf-8"); RequestBody httpRequestBody = RequestBody.create(requestBody.toString(), jsonMediaType); // 处理认证:如果有token,拼在URL里或者用Authorization头 String uploadApiUrl = jupyterBaseUrl + "/api/contents/" + targetNotebookName; if (jupyterAuthToken != null && !jupyterAuthToken.isBlank()) { uploadApiUrl += "?token=" + jupyterAuthToken; // 或者用Authorization头:.addHeader("Authorization", "token " + jupyterAuthToken) } Request request = new Request.Builder() .url(uploadApiUrl) .put(httpRequestBody) .build(); // 第四步:发送请求并处理响应 try (Response response = client.newCall(request).execute()) { if (response.isSuccessful()) { System.out.println("笔记本上传成功!"); System.out.println("服务器响应:" + response.body().string()); } else { System.err.println("上传失败,状态码:" + response.code()); System.err.println("错误详情:" + response.body().string()); } } } }
关键注意事项
content字段的正确用法:直接把本地ipynb文件解析后的JSONObject赋值给content,不要做额外的字符串包装,否则服务器会把嵌套的字符串当成无效内容。- 字段类型严格匹配:Jupyter API对字段类型要求很严,比如
writable必须是布尔值,format必须是"json"(针对notebook类型)。 - 认证必须正确:如果你的Jupyter Server开启了token认证,一定要在请求中携带token,否则会返回403禁止访问。
- 调试技巧:如果还是失败,打印最终发送的
requestBody.toString(),对比Postman手动请求的正确体,看哪里有差异;同时查看服务器的日志,里面会有详细的错误原因。
内容的提问来源于stack exchange,提问作者Pradip Karad
相关产品推荐
相关产品推荐

