Skip to content

Latest commit

 

History

History
104 lines (90 loc) · 7.43 KB

File metadata and controls

104 lines (90 loc) · 7.43 KB

novada-java 开发计划

将 Go SDK novada-go 移植为功能等价、风格地道的 Java 库,通过 Maven 发布到 Maven Central。 本计划与 PROMPT.md 配套:PROMPT 给 Claude Code 当系统级指令,PLAN 给人看进度与验收。

关键设计映射(从 Go 源码提取)

Go 设计 Java 对应
顶层 Client,三个 baseURL + Bearer 注入 + 重试 NovadaClient.builder(apiKey).baseUrl(...).maxRetries(...).build()
Functional Options (WithTimeout...) Builder 模式
可替换 http.Client 注入自定义 java.net.http.HttpClient,默认内部构造
context.Context(取消/超时) 每请求 HttpRequest.timeout(...);无取消原语,仅超时
子包 + transport.Doer 接口解耦 内部 Transport,子服务持有其引用,挂在 client.proxy()/.scraper()/.wallet()
参数 struct + 必填校验 → ValidationError 不可变 Params(record 或 Builder)+ 校验抛 ValidationException
统一响应包 {code,data,msg,timestamp},仅 code==0 成功 Envelope.decode(Jackson),code!=0ApiException
APIError + IsAuthError/IsRateLimited/CodeOf NovadaException → ApiException → AuthException/RateLimitExceptioninstanceof + code()/httpStatus()
两套编码:multipart / x-www-form-urlencoded 手写 multipart body builder / URLEncoder(含 Raw 变体)
重试只针对网络错误 + 429/5xx,绝不重试业务 code 同语义(IOException + 429/5xx)
抓取响应格式不定,返回原始文本 doRequest() 返回 ScrapeResponse{raw};Google 走结构化解码
仅标准库 HTTP 用 JDK HttpClient;仅 Jackson 一个第三方运行时依赖

准备工作

  • reference/novada-go/:Go 源码(*.goREADME.mdnovada-go-sdk-spec.md)。
  • reference/openapi/novada-openapi.jsonwebunblocker_openapi.jsonSerpapi_openapi.json。 (用仓库根的 scripts/sync_reference.sh 同步,见文末。)
  • 确认 Maven 坐标(groupId/artifactId)、包根命名空间、发布仓库(Central / 内部 Nexus)。

里程碑

M0 — 脚手架与基础设施(半天)

  • pom.xml(Java 17、jackson-databind、JUnit 5、Spotless(google-java-format)、surefire、 可选 sources/javadoc 插件)、LICENSE(MIT)、Version.javainternal/Json.java(共享 ObjectMapper, 关 FAIL_ON_UNKNOWN_PROPERTIES)。
  • exception/NovadaException / ApiException / AuthException / RateLimitException / ValidationException
  • internal/Envelope.java:envelope 解码 + code!=0ApiException + list 解包 helper。
  • internal/Transport.javadoMultipart / doFormUrlencoded(含 Raw 变体)、用 HttpClientHttpRequest(POST)、Bearer 注入、Accept/User-Agent 头、线性退避重试(仅 IOException + 429/5xx)、 joinUrl、非 2xx → AuthException/RateLimitException/ApiException。手写 multipart boundary 编码。
  • NovadaClient.java + Builder:构造、三 baseURL、env 回退(System.getenv("NOVADA_API_KEY"))、 默认 HttpClient、子服务装配(先留空)。
  • 验收:JUnit + JDK HttpServer mock 一个 white_list/list,断言 Bearer 头、multipart body、 envelope 解包、code!=0ApiExceptionmvn spotless:check verify 全绿。

M1 — Proxy 最小闭环(半天)

  • internal/FormBuilder.java(req/opt 系列)、internal/Validator.java、分页默认值。
  • proxy/WhitelistService.java + proxy/AccountService.java,对应 model/ 的 Params/返回类型 + Product enum。
  • 验收:每个方法成功路径 + ValidationException(必填缺失)单测;确立"Params(record/Builder) + 校验 + multipart 编码 + Jackson 解码"的可复制模式。

M2 — Proxy 全量铺开(1.5–2 天)

  • 依据 novada-openapi.json 的 requestBody properties,批量生成 Residential / Mobile / RotatingIsp / RotatingDc / StaticIsp / DedicatedDc / Unlimited / ProhibitDomain 的方法、Params、返回类型与必填校验。
  • 注意:导出类(静态 IP export)返回文件流 → 用 Raw 变体不走 envelope(对应 Go 的 DoMultipartRaw), 返回 byte[]
  • 共享 model:TimeRangeFlowBalanceFlowConsumeLog 等。
  • 验收:每个子服务至少一个编码 + 解包单测;Spotless 通过。

M3 — Scraper 通用驱动(半天)

  • scraper/ScraperService.javaTarget 枚举、ScrapeRequest/ScrapeResponsedoRequest()scraper_params = Json.write(params)URLEncoder 编码,按 target 选 host,返回 ScrapeResponse{raw})、 必填校验抛 ValidationException
  • 验收:单测断言 urlencoded body、scraper_params JSON、host 路由 (ScraperAPI vs WebUnblocker)、scraper_errors

M4 — Scraper 强类型 + 查询接口(半天)

  • api().youtube().videoPost(薄封装 doRequest)、api().google().search扁平 form 字段 + envelope 结构化解码,对应 GoogleSearchResult/Datajson 字段保留为 JsonNode/原始)。
  • unblocker().scrape(发 target_url/response_format/js_render/country/wait_ms, 解码 UnblockerResult:html/code/msg/msgDetail/useBalance)。
  • 走通用 host 的查询:unblocker().countries()browser().countries()universal().balance()universal().unit()
  • 验收:Google 结构化解码单测;unblocker scrape 字段单测;查询接口走通用 host 验证。

M5 — Wallet(半天)

  • wallet().balance()wallet().usageRecord(...)(分页默认 1/10)。
  • 验收:单测覆盖分页默认值 + 解码。

M6 — 文档、示例、CI、发布(半天)

  • README.md:Maven/Gradle 依赖坐标、quick start、三 baseURL 表、proxy/scraper/wallet 各一例、 错误处理示例(对齐 Go 版)。
  • examples/:proxy / scraper / wallet 各一个可运行示例(读 NOVADA_API_KEY)。
  • .github/workflows/ci.yml:Java 17/21 矩阵,mvn -B verify
  • 发布元数据:sources-jar、javadoc-jar、GPG 签名、distributionManagement/central-publishing 说明; 完善 POM 的 name/description/url/licenses/scm/developers
  • 验收mvn -B verify 通过;本地示例可跑;POM 满足 Central 校验要求。

风险与注意点

  • OpenAPI 是字段真相:表单字段以 novada-openapi.json 的 requestBody 为准,逐字段核对必填/可选。
  • code == 0 才成功:最容易踩的坑,不要用 HTTP 200 判断。
  • 空值省略语义:可选字段 null/空字符串/0 不发送;三态布尔用 Boolean(可 null)。
  • 抓取响应不解 envelope(除 Google Search 外),格式不定,原样返回。
  • 重试边界:业务 code!=0 永不重试;只重试 IOException 与 429/5xx。
  • multipart 手写:JDK HttpClient 无内置 multipart 编码,需手写 boundary + 字段;注意空值省略、 正确的 Content-Type(含 boundary)。urlencoded 用 URLEncoder.encode(..., UTF_8)
  • 线程安全:client 与子服务无可变共享状态,可被多线程复用(对应 Go 的并发安全)。
  • 命名冲突:Go 的 Do 在 Java 用 doRequestcode()Throwable 无冲突(Go 的 CodeOf → ApiException.code())。

参考同步脚本

仓库根的 scripts/sync_reference.sh 会把 Go 项目源码与 OpenAPI 拷入 reference/。 如 Go 项目路径不同,编辑脚本顶部的 GO_SRC 变量。