使用apifox工具获得掘金的发帖接口

175 阅读8分钟

使用apifox工具获得掘金的发帖接口

掘金相对于csdn来说,是先创建文章(api.juejin.cn/content_api…),返回一个文章id

然后拿着这个文章id作为draft_id,调用发帖服务(api.juejin.cn/content_api…),才能完成文章的发送

注意哦:(参考下图)

  • 分类id(category_id)和标签id(tag_ids)是必填项
  • 编辑摘要(brief_content)必须是50-100字,不然后面测试的时候会报参数错误

:::

通过ai工具生成相应的DTO与Service

@Data
public class JueJinCreateRequest {
    private String category_id="6809637769959178254";
    private List<String> tag_ids= Collections.singletonList("6809640408797167623");
    private String link_url="";
    private String cover_image="";
    private String title;
    private String brief_content="11111111111111111111111111111111111111111111111111111111111111111111111111111111";
    private Integer edit_type=10;
    private String html_content="deprecated";
    private String mark_content;
    private List<String> theme_ids=new ArrayList<>();
    private List<String> pics=new ArrayList<>();
}
@Data
public class JueJinCreateResponse {
    private Integer err_no;
    private String err_msg;
    private ArticleData data;

    @Data
    public static class ArticleData {
        private String id;
        private String article_id;
        private String user_id;
        private String category_id;
        private List<String> tag_ids;
        private String link_url;
        private String cover_image;
        private Integer is_gfw;
        private String title;
        private String brief_content;
        private Integer is_english;
        private Integer is_original;
        private Integer edit_type;
        private String html_content;
        private String mark_content;
        private String ctime;
        private String mtime;
        private Integer status;
        private Integer original_type;
        private List<String> theme_ids;
    }
}
@Data
public class JueJinPublishRequest {
    private String draft_id;
    private Boolean sync_to_org=false;
    private List<String> column_ids=new ArrayList<>();
    private List<String> theme_ids=new ArrayList<>();
    private Integer encrypted_word_count=1077879;
    private Integer origin_word_count=7;
}
@Data
public class JueJinPublishResponse {
    private Integer err_no;
    private String err_msg;
    private ArticleData data;

    @Data
    public static class ArticleData {
        private String article_id;
        private String user_id;
        private String category_id;
        private List<String> tag_ids;
        private Integer visible_level;
        private String link_url;
        private String cover_image;
        private Integer is_gfw;
        private String title;
        private String brief_content;
        private Integer is_english;
        private Integer is_original;
        private Integer user_index;
        private Integer original_type;
        private String original_author;
        private String content;
        private String ctime;
        private String mtime;
        private String rtime;
        private Integer status;
        private Integer verify_status;
        private Integer audit_status;
        private String mark_content;
        private String org_id;
        private Integer homepage_top_time;
        private Integer homepage_top_status;
    }
}

API服务接口

public interface IJueJinService {
    
    /**
     * 创建文章
     * 
     * @param cookie Cookie信息
     * @param authorization 授权信息
     * @param request 创建请求
     * @return 创建响应
     */
    @POST("content_api/v1/article_draft/create")
    Call<JueJinCreateResponse> createArticle(
            @Header("Cookie") String cookie,
            @Header("authorization") String authorization,
            @Body JueJinCreateRequest request
    );
    
    /**
     * 发布文章
     * 
     * @param cookie Cookie信息
     * @param authorization 授权信息
     * @param request 发布请求
     * @return 发布响应
     */
    @POST("content_api/v1/article/publish")
    Call<JueJinPublishResponse> publishArticle(
            @Header("Cookie") String cookie,
            @Header("authorization") String authorization,
            @Body JueJinPublishRequest request
    );
}

创建IJueJinService接口的实现类实例

@Bean
public IJueJinService jueJinService(OkHttpClient okHttpClient) {
    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("https://api.juejin.cn/")
            .client(okHttpClient)
            .addConverterFactory(JacksonConverterFactory.create())
            .build();

    return retrofit.create(IJueJinService.class);
}

配置HTTP客户端配置类

@Configuration
public class HttpClientConfig {

    /**
     * 配置OkHttpClient
     *
     * @return OkHttpClient实例
     */
    @Bean
    public OkHttpClient okHttpClient() {
        return new OkHttpClient.Builder()
                .addInterceptor(new ContentTypeInterceptor())
                .build();
    }

    /**
     * Content-Type拦截器
     * 为所有请求添加Content-Type: application/json头
     */
    static class ContentTypeInterceptor implements Interceptor {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request originalRequest = chain.request();

            // 为请求添加Content-Type头
            Request newRequest = originalRequest.newBuilder()
                    .header("Content-Type", "application/json")
                    .build();

            return chain.proceed(newRequest);
        }
    }
}

之后就可以进行接口调用测试了

测试接口

@RunWith(SpringRunner.class)
@SpringBootTest
@Slf4j
public class APITest {

    @Autowired
    private IJueJinService jueJinService;

    @Resource
    private JueJinApiProperties juejinApiProperties;

    /**
     * 创建文章
     *
     * @throws IOException
     */
    @Test
    public void testCreateArticle() throws IOException {
        // 准备请求数据
        JueJinCreateRequest request = new JueJinCreateRequest();
        request.setCategory_id("6809637769959178254"); // 后端
        request.setTag_ids(Arrays.asList("6809640408797167623")); // Java
        request.setLink_url("");
        request.setCover_image("");
        request.setTitle("Java开发实践:掘金API集成测试");
        request.setBrief_content("本文介绍了如何使用Java集成掘金API进行文章发布本文介绍了如何使用Java集成掘金API进行文章发布");
        request.setEdit_type(10); // Markdown编辑模式
        request.setHtml_content("deprecated");
        request.setMark_content("hello");
        request.setTheme_ids(new ArrayList<>());
        request.setPics(new ArrayList<>());

        // 设置Cookie和授权信息(实际测试时需要替换为真实值)
        String cookie = juejinApiProperties.getCookie();
        String authorization = juejinApiProperties.getAuthorization();

        // 调用API
        Call<JueJinCreateResponse> call = jueJinService.createArticle(cookie, authorization, request);
        log.info("Sending request to JueJin API: {}", request);

        // 执行请求并验证响应
        Response<JueJinCreateResponse> response = call.execute();
        log.info("Received response from JueJin API: {}", response.body());

        // 验证响应
        if (response.isSuccessful() && response.body() != null) {
            JueJinCreateResponse responseBody = response.body();
            assertEquals(0, responseBody.getErr_no().intValue());
            assertEquals("success", responseBody.getErr_msg());
            assertNotNull(responseBody.getData());
            assertNotNull(responseBody.getData().getId());
            System.out.println(responseBody.getData().getId());
        } else {
            log.error("API call failed: {}", response.errorBody() != null ? response.errorBody().string() : "Unknown error");
        }
    }

    /**
     * 发布文章
     *
     * @throws IOException
     */
    @Test
    public void testPublishArticle() throws IOException {
        // 准备请求数据
        JueJinPublishRequest request = new JueJinPublishRequest();
        request.setDraft_id("7490003622233489435"); // 草稿ID,实际测试时需要替换为真实值
        request.setSync_to_org(false);
        request.setColumn_ids(new ArrayList<>());
        request.setTheme_ids(new ArrayList<>());
        request.setEncrypted_word_count(1077885);
        request.setOrigin_word_count(1);

        // 设置Cookie和授权信息(实际测试时需要替换为真实值)
        String cookie = juejinApiProperties.getCookie();
        String authorization = juejinApiProperties.getAuthorization();

        // 调用API
        Call<JueJinPublishResponse> call = jueJinService.publishArticle(cookie, authorization, request);
        log.info("Sending publish request to JueJin API: {}", request);

        // 执行请求并验证响应
        Response<JueJinPublishResponse> response = call.execute();
        log.info("Received response from JueJin API: {}", response.body());

        // 验证响应
        if (response.isSuccessful() && response.body() != null) {
            JueJinPublishResponse responseBody = response.body();
            assertEquals(0, responseBody.getErr_no().intValue());
            assertEquals("success", responseBody.getErr_msg());
            assertNotNull(responseBody.getData());
            assertNotNull(responseBody.getData().getArticle_id());
        } else {
            log.error("API call failed: {}", response.errorBody() != null ? response.errorBody().string() : "Unknown error");
        }
    }

!其中JueJinApiProperties相比csdn来说添加了authorization这个参数,yml文件别忘配!

接口测试通过就可以进行下一步了

整合服务

接下来要做的就是把创建文章(create)与发表文章(publish)的接口结合起来

domain层还是沿用小傅哥的例子

infrastructure层进行writeArticle方法的编写

@Override
public ArticleFunctionResponse writeArticle(ArticleFunctionRequest request) throws IOException {
    // 创建文章
    JueJinCreateRequest articleRequestDTO = new JueJinCreateRequest();
    articleRequestDTO.setTitle(request.getTitle());
    articleRequestDTO.setMark_content(request.getMarkdowncontent());
    if (request.getMarkdowncontent().length() > 50) {
        articleRequestDTO.setBrief_content(request.getMarkdowncontent().substring(0, 70)); // 取前70个字符 (要求:50-100)
    }

    Call<JueJinCreateResponse> call = juejinService.createArticle(juejinApiProperties.getCookie(), juejinApiProperties.getAuthorization(), articleRequestDTO);

    Response<JueJinCreateResponse> response = call.execute();

    log.info("请求JueJin创建文章 \nreq:{} \nres:{}", JSON.toJSONString(articleRequestDTO), JSON.toJSONString(response));

    if (!response.isSuccessful()) {
        return null;
    }

    JueJinCreateResponse articleResponseDTO = response.body();
    if (articleResponseDTO == null) {
        return null;
    }

    ArticleFunctionResponse articleFunctionResponse = new ArticleFunctionResponse();
    articleFunctionResponse.setCode(articleResponseDTO.getErr_no());
    articleFunctionResponse.setMsg(articleResponseDTO.getErr_msg());

    // 发送文章
    JueJinPublishRequest jueJinPublishRequest = new JueJinPublishRequest();
    jueJinPublishRequest.setDraft_id(articleResponseDTO.getData().getId());
    Call<JueJinPublishResponse> jueJinPublishResponseCall = juejinService.publishArticle(juejinApiProperties.getCookie(), juejinApiProperties.getAuthorization(), jueJinPublishRequest);
    Response<JueJinPublishResponse> jueJinPublishResponse = jueJinPublishResponseCall.execute();
    if (!jueJinPublishResponse.isSuccessful()) {
        return null;

    }

    JueJinPublishResponse jueJinPublishResponseBody = jueJinPublishResponse.body();
    if (jueJinPublishResponseBody != null) {
        articleFunctionResponse.setCode(jueJinPublishResponseBody.getErr_no());
        articleFunctionResponse.setMsg(jueJinPublishResponseBody.getErr_msg());
    }
    return articleFunctionResponse;
}

最后对整合后的接口测试

@Test
public void testSaveArticle_domain() throws IOException {
    String json = "{\"content\":\"<h2>场景:</h2>\\n<p>在某互联网大厂的面试室,一位严肃的面试官正准备提问,而对面坐着一位看似紧张却又想显得轻松的程序员小张。</p>\\n<p><strong>面试官</strong>:我们先来聊聊Java核心知识。第一个问题,Java中的JVM是如何管理内存的?</p>\\n<p><strong>程序员小张</strong>:哦,这个简单!JVM就像一个巨大的购物车,负责把所有的变量都放进去,呃……然后就……管理起来?</p>\\n<p><strong>面试官</strong>:嗯,第二个问题,请说说HashMap的工作原理。</p>\\n<p><strong>程序员小张</strong>:HashMap嘛,就是……呃,一个很大的箱子,大家都往里面扔东西,有时候会打架……</p>\\n<p><strong>面试官</strong>:那么第三个问题,能不能讲讲Spring和SpringBoot的区别?</p>\\n<p><strong>程序员小张</strong>:Spring是……呃,春天?SpringBoot就是穿靴子的春天嘛!哈哈……</p>\\n<p><strong>面试官</strong>:好,今天的问题就问到这里。回去等通知吧。</p>\\n<h2>答案解析:</h2>\\n<ol>\\n<li>\\n<p><strong>JVM内存管理</strong>:JVM内存管理包括堆内存和栈内存,堆内存用于存储对象实例,栈内存用于执行线程时的栈帧。</p>\\n</li>\\n<li>\\n<p><strong>HashMap原理</strong>:HashMap通过哈希函数将键映射到对应的值,并通过链表解决哈希冲突。</p>\\n</li>\\n<li>\\n<p><strong>Spring与SpringBoot区别</strong>:Spring是一个大型应用框架,而SpringBoot是基于Spring的快速开发套件,简化了Spring应用的配置。</p>\\n</li>\\n</ol>\\n\",\"cover_images\":[],\"cover_type\":0,\"description\":\"在互联网大厂的面试中,严肃的面试官与搞笑的程序员上演了一场精彩的对话。面试官提出Java核心知识、HashMap、Spring等问题,程序员则用幽默的方式作答。本文不仅展现了轻松的面试氛围,还附上了详细的技术问题答案解析,帮助读者更好地理解相关知识。\",\"is_new\":1,\"level\":\"0\",\"markdowncontent\":\"## 场景:\\n\\n在某互联网大厂的面试室,一位严肃的面试官正准备提问,而对面坐着一位看似紧张却又想显得轻松的程序员小张。\\n\\n**面试官**:我们先来聊聊Java核心知识。第一个问题,Java中的JVM是如何管理内存的?\\n\\n**程序员小张**:哦,这个简单!JVM就像一个巨大的购物车,负责把所有的变量都放进去,呃……然后就……管理起来?\\n\\n**面试官**:嗯,第二个问题,请说说HashMap的工作原理。\\n\\n**程序员小张**:HashMap嘛,就是……呃,一个很大的箱子,大家都往里面扔东西,有时候会打架……\\n\\n**面试官**:那么第三个问题,能不能讲讲Spring和SpringBoot的区别?\\n\\n**程序员小张**:Spring是……呃,春天?SpringBoot就是穿靴子的春天嘛!哈哈……\\n\\n**面试官**:好,今天的问题就问到这里。回去等通知吧。\\n\\n## 答案解析:\\n\\n1. **JVM内存管理**:JVM内存管理包括堆内存和栈内存,堆内存用于存储对象实例,栈内存用于执行线程时的栈帧。\\n\\n2. **HashMap原理**:HashMap通过哈希函数将键映射到对应的值,并通过链表解决哈希冲突。\\n\\n3. **Spring与SpringBoot区别**:Spring是一个大型应用框架,而SpringBoot是基于Spring的快速开发套件,简化了Spring应用的配置。\",\"not_auto_saved\":\"0\",\"pubStatus\":\"draft\",\"readType\":\"public\",\"resource_id\":\"\",\"resource_url\":\"\",\"source\":\"pc_mdeditor\",\"status\":0,\"sync_git_code\":0,\"tags\":\"Java,面试,互联网,程序员,Spring,SpringBoot,HashMap,JVM\",\"title\":\"互联网大厂Java面试:严肃面试官与搞笑程序员的对决\",\"vote_id\":0}";
    ArticleFunctionRequest request = JSON.parseObject(json, ArticleFunctionRequest.class);
    ArticleFunctionResponse response = jueJinArticleService.saveArticle(request);
    log.info("测试结果:{}", JSON.toJSONString(response));
}

完美收工 ^_^