halo-dev / halo

强大易用的开源建站工具。
https://www.halo.run
GNU General Public License v3.0
32.71k stars 9.49k forks source link

尝试调用API更新文章信息,API调用失败 #5293

Closed musnows closed 5 months ago

musnows commented 5 months ago

系统信息

使用的哪种方式运行?

Docker

在线站点地址

https://halo.musnow.top/

发生了什么?

PUT调用更新文章信息失败

如题,我根据vscode插件的更新api调用逻辑尝试调用,文章内容可以被更新,但是文章信息调用失败

参考的vscode插件代码如下

if (params.post.metadata.name) {
        const { name } = params.post.metadata;
        await this.apiClient.put(
          `/apis/content.halo.run/v1alpha1/posts/${name}`,
          params.post
        );
        await this.apiClient.put(
          `/apis/api.console.halo.run/v1alpha1/posts/${name}/content`,
          params.content
        );
      }

我的python代码如下,详见 https://github.com/musnows/hexo-to-halo2/blob/a8b29459e342154211c8d404a287745957b34bd9/utils/Halo2Uploader.py#L33-L104

BASE_URL = UserConfig["haloSite"]
API_KEY = UserConfig["userToken"]
BASE_HEADER = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json"
}
def update_page(raw_content: str,
                title: str,
                slug: str,
                cover: str,
                categories: list[str],
                tags: list[str],
                pinned: bool = False,
                allow_comment: bool = True,
                is_public: bool = True,
                publish_time=None):
    """如果该文章已有,则调用update方法"""
    try:
        posts_url = f"/apis/api.console.halo.run/v1alpha1/posts/{slug}"
        posts_url_content = posts_url + "/content"
        data = {
            "post": {
                "spec": {
                    "title": title,
                    "slug": slug,
                    "template": "",
                    "cover": cover,
                    "deleted": False,
                    "publish": False,
                    "publishTime": publish_time,
                    "pinned": pinned,
                    "allowComment": allow_comment,
                    "visible": "PUBLIC" if is_public else "PRIVATE",
                    "priority": 0,
                    "excerpt": {
                        "autoGenerate": True,
                        "raw": ""
                    },
                    "categories": categories,
                    "tags": tags,
                    "htmlMetas": []
                },
                "apiVersion": "content.halo.run/v1alpha1",
                "kind": "Post",
                "metadata": {
                    "name": slug
                }
            },
            "content": {
                "raw": raw_content,
                "content": render_markdown(raw_content),
                "rawType": "markdown"
            }
        }
        # 更新
        ret1 = requests.put(url=BASE_URL + posts_url,
                            json=data["post"],
                            headers=BASE_HEADER)  # 这里要用json来传data
        ret2 = requests.put(url=BASE_URL + posts_url_content,
                            json=data["content"],
                            headers=BASE_HEADER)  # 这里要用json来传data
        return (ret1.json(), ret2.json())
    except:
        print(traceback.format_exc())
        return (None,None)

调用该函数时,第一个API调用失败,第二个content内容API调用成功

ret = update_page(
    "test md content\n# 这是一个测试\n内容如下", "修改后的标题",
    "971003431", "https://img.musnow.top/i/2023/04/64302610057ae.png",
    ["category-wsAUf"], ["tag-gfXTb", "tag-wqREq"])
print(ret[0], '\n', ret[1])

第一个API返回错误信息如下,第二个API返回的是正常结果。

{'type': 'about:blank', 'title': 'Internal Server Error', 'status': 500, 'detail': 'Something went wrong, please try again later.', 'instance': 'https://halo.musnow.top/apis/api.console.halo.run/v1alpha1/posts/971003431', 'requestId': '9a95c9d8-228', 'timestamp': '2024-01-31T09:22:23.373912616Z'}

可以观察到的结果是文章的内容在编辑器中已经被正常修改,但是文章的标题信息没有变化。因为还没有调用publish接口,所以网站展示的文章内容也没有变化。

image

分组和tag重名问题

另外还有一个问题,个人认为tags和categories接口在创建新的tag和分组的时候应该检查名字,如果名字已存在应该返回已有信息而不是新建一个tag或分组。

T$_IVU3KNK$2LPGHRC%{4_4 @CH{EA ZQ61X(M$XXZ YY%M

相关日志输出

2024-01-31T17:22:23.374+08:00 ERROR 7 --- [reactor-http-epoll-1] a.w.r.e.AbstractErrorWebExceptionHandler : [9a95c9d8-228]  500 Server Error for HTTP PUT "/apis/api.console.halo.run/v1alpha1/posts/971003431"

java.lang.NullPointerException: Cannot invoke "run.halo.app.core.extension.content.Post.getSpec()" because "post" is null
    at run.halo.app.content.impl.PostServiceImpl.updatePost(PostServiceImpl.java:234) ~[classes/:2.11.3]
    Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: 
Error has been observed at the following site(s):
    *__checkpoint ⇢ run.halo.app.security.InitializeRedirectionWebFilter [DefaultWebFilterChain]
    *__checkpoint ⇢ run.halo.app.security.authentication.login.UsernamePasswordLogoutHandler [DefaultWebFilterChain]
    *__checkpoint ⇢ run.halo.app.security.authentication.login.DelegatingLogoutPageGeneratingWebFilter [DefaultWebFilterChain]
    *__checkpoint ⇢ run.halo.app.security.authentication.login.UsernamePasswordAuthenticator [DefaultWebFilterChain]
    *__checkpoint ⇢ AuthorizationWebFilter [DefaultWebFilterChain]
    *__checkpoint ⇢ ExceptionTranslationWebFilter [DefaultWebFilterChain]
    *__checkpoint ⇢ LogoutWebFilter [DefaultWebFilterChain]
    *__checkpoint ⇢ ServerRequestCacheWebFilter [DefaultWebFilterChain]
    *__checkpoint ⇢ SecurityContextServerWebExchangeWebFilter [DefaultWebFilterChain]
    *__checkpoint ⇢ AnonymousAuthenticationWebFilter [DefaultWebFilterChain]
    *__checkpoint ⇢ AuthenticationWebFilter [DefaultWebFilterChain]
    *__checkpoint ⇢ AuthenticationWebFilter [DefaultWebFilterChain]
    *__checkpoint ⇢ ReactorContextWebFilter [DefaultWebFilterChain]
    *__checkpoint ⇢ CsrfWebFilter [DefaultWebFilterChain]
    *__checkpoint ⇢ CorsWebFilter [DefaultWebFilterChain]
    *__checkpoint ⇢ HttpHeaderWriterWebFilter [DefaultWebFilterChain]
    *__checkpoint ⇢ ServerWebExchangeReactorContextWebFilter [DefaultWebFilterChain]
    *__checkpoint ⇢ OrderedWebFilter [DefaultWebFilterChain]
    *__checkpoint ⇢ OrderedWebFilter [DefaultWebFilterChain]
    *__checkpoint ⇢ OrderedWebFilter [DefaultWebFilterChain]
    *__checkpoint ⇢ org.springframework.security.web.server.WebFilterChainProxy [DefaultWebFilterChain]
    *__checkpoint ⇢ HTTP PUT "/apis/api.console.halo.run/v1alpha1/posts/971003431" [ExceptionHandlingWebHandler]
Original Stack Trace:
        at run.halo.app.content.impl.PostServiceImpl.updatePost(PostServiceImpl.java:234) ~[classes/:2.11.3]
        at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:132) ~[reactor-core-3.6.0.jar:3.6.0]
        at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79) ~[reactor-core-3.6.0.jar:3.6.0]
        at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79) ~[reactor-core-3.6.0.jar:3.6.0]
        at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:158) ~[reactor-core-3.6.0.jar:3.6.0]
        at reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.onNext(FluxContextWrite.java:107) ~[reactor-core-3.6.0.jar:3.6.0]
        at reactor.core.publisher.FluxMapFuseable$MapFuseableConditionalSubscriber.onNext(FluxMapFuseable.java:299) ~[reactor-core-3.6.0.jar:3.6.0]
        at reactor.core.publisher.FluxFilterFuseable$FilterFuseableConditionalSubscriber.onNext(FluxFilterFuseable.java:337) ~[reactor-core-3.6.0.jar:3.6.0]
        at reactor.core.publisher.Operators$BaseFluxToMonoOperator.completePossiblyEmpty(Operators.java:2097) ~[reactor-core-3.6.0.jar:3.6.0]
        at reactor.core.publisher.MonoCollect$CollectSubscriber.onComplete(MonoCollect.java:145) ~[reactor-core-3.6.0.jar:3.6.0]
        at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:144) ~[reactor-core-3.6.0.jar:3.6.0]
        at reactor.core.publisher.FluxPeek$PeekSubscriber.onComplete(FluxPeek.java:260) ~[reactor-core-3.6.0.jar:3.6.0]
        at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:144) ~[reactor-core-3.6.0.jar:3.6.0]
        at reactor.netty.channel.FluxReceive.terminateReceiver(FluxReceive.java:483) ~[reactor-netty-core-1.1.13.jar:1.1.13]
        at reactor.netty.channel.FluxReceive.drainReceiver(FluxReceive.java:275) ~[reactor-netty-core-1.1.13.jar:1.1.13]
        at reactor.netty.channel.FluxReceive.request(FluxReceive.java:133) ~[reactor-netty-core-1.1.13.jar:1.1.13]
        at reactor.core.publisher.FluxMap$MapSubscriber.request(FluxMap.java:164) ~[reactor-core-3.6.0.jar:3.6.0]
        at reactor.core.publisher.FluxPeek$PeekSubscriber.request(FluxPeek.java:138) ~[reactor-core-3.6.0.jar:3.6.0]
        at reactor.core.publisher.FluxMap$MapSubscriber.request(FluxMap.java:164) ~[reactor-core-3.6.0.jar:3.6.0]
        at reactor.core.publisher.Operators$BaseFluxToMonoOperator.request(Operators.java:2067) ~[reactor-core-3.6.0.jar:3.6.0]
        at reactor.core.publisher.FluxFilterFuseable$FilterFuseableConditionalSubscriber.request(FluxFilterFuseable.java:411) ~[reactor-core-3.6.0.jar:3.6.0]
        at reactor.core.publisher.FluxMapFuseable$MapFuseableConditionalSubscriber.request(FluxMapFuseable.java:360) ~[reactor-core-3.6.0.jar:3.6.0]
        at reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.request(FluxContextWrite.java:136) ~[reactor-core-3.6.0.jar:3.6.0]
        at reactor.core.publisher.MonoFlatMap$FlatMapMain.request(MonoFlatMap.java:194) ~[reactor-core-3.6.0.jar:3.6.0]
        at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.set(Operators.java:2367) ~[reactor-core-3.6.0.jar:3.6.0]
        at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onSubscribe(FluxOnErrorResume.java:74) ~[reactor-core-3.6.0.jar:3.6.0]
        at reactor.core.publisher.MonoFlatMap$FlatMapMain.onSubscribe(MonoFlatMap.java:117) ~[reactor-core-3.6.0.jar:3.6.0]
        at reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.onSubscribe(FluxContextWrite.java:101) ~[reactor-core-3.6.0.jar:3.6.0]
        at reactor.core.publisher.FluxMapFuseable$MapFuseableConditionalSubscriber.onSubscribe(FluxMapFuseable.java:265) ~[reactor-core-3.6.0.jar:3.6.0]
        at reactor.core.publisher.FluxFilterFuseable$FilterFuseableConditionalSubscriber.onSubscribe(FluxFilterFuseable.java:305) ~[reactor-core-3.6.0.jar:3.6.0]
        at reactor.core.publisher.Operators$BaseFluxToMonoOperator.onSubscribe(Operators.java:2051) ~[reactor-core-3.6.0.jar:3.6.0]
        at reactor.core.publisher.FluxMap$MapSubscriber.onSubscribe(FluxMap.java:92) ~[reactor-core-3.6.0.jar:3.6.0]
        at reactor.core.publisher.FluxPeek$PeekSubscriber.onSubscribe(FluxPeek.java:171) ~[reactor-core-3.6.0.jar:3.6.0]
        at reactor.core.publisher.FluxMap$MapSubscriber.onSubscribe(FluxMap.java:92) ~[reactor-core-3.6.0.jar:3.6.0]
        at reactor.netty.channel.FluxReceive.startReceiver(FluxReceive.java:172) ~[reactor-netty-core-1.1.13.jar:1.1.13]
        at reactor.netty.channel.FluxReceive.lambda$subscribe$2(FluxReceive.java:150) ~[reactor-netty-core-1.1.13.jar:1.1.13]
        at io.netty.util.concurrent.AbstractEventExecutor.runTask(AbstractEventExecutor.java:173) ~[netty-common-4.1.101.Final.jar:4.1.101.Final]
        at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:166) ~[netty-common-4.1.101.Final.jar:4.1.101.Final]
        at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:470) ~[netty-common-4.1.101.Final.jar:4.1.101.Final]
        at io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:413) ~[netty-transport-classes-epoll-4.1.101.Final.jar:4.1.101.Final]
        at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997) ~[netty-common-4.1.101.Final.jar:4.1.101.Final]
        at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[netty-common-4.1.101.Final.jar:4.1.101.Final]
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-common-4.1.101.Final.jar:4.1.101.Final]
        at java.base/java.lang.Thread.run(Unknown Source) ~[na:na]

附加信息

No response

JohnNiang commented 5 months ago

Hi @musnows , thank you for reaching out here!

更新文章时传入的 Body 有问题,可以试着更新这行代码:https://github.com/musnows/hexo-to-halo2/blob/a8b29459e342154211c8d404a287745957b34bd9/utils/Halo2Uploader.py#L96

- json=data["post"],
+ json=data,

目前尚不清楚 VSCode 插件中是否调用正确,需要 @ruibaby 确认一下。

ruibaby commented 5 months ago

建议提供请求的 payload,以及异常信息,当前无法判断。

目前尚不清楚 VSCode 插件中是否调用正确

没有问题,和 Console 一致。

另外还有一个问题,个人认为tags和categories接口在创建新的tag和分组的时候应该检查名字,如果名字已存在应该返回已有信息而不是新建一个tag或分组。

当前 Extension 生成的 API 不支持校验其他字段的唯一性,建议在创建之前先获取所有分类或者标签并匹配,没有匹配到才创建。

musnows commented 5 months ago

Hi @musnows , thank you for reaching out here!

更新文章时传入的 Body 有问题,可以试着更新这行代码:https://github.com/musnows/hexo-to-halo2/blob/a8b29459e342154211c8d404a287745957b34bd9/utils/Halo2Uploader.py#L96

- json=data["post"],
+ json=data,

目前尚不清楚 VSCode 插件中是否调用正确,需要 @ruibaby 确认一下。

已尝试去掉post,依旧是内部错误。

@ruibaby 请求的data完整载荷如下

{
    "post": {
        "spec": {
            "title": "修改后的标题",
            "slug": "971003431",
            "template": "",
            "cover": "https://img.musnow.top/i/2023/04/64302610057ae.png",
            "deleted": false,
            "publish": false,
            "publishTime": "2023-08-02T07:52:14Z",
            "pinned": false,
            "allowComment": true,
            "visible": "PUBLIC",
            "priority": 0,
            "excerpt": {
                "autoGenerate": true,
                "raw": ""
            },
            "categories": [
                "category-wsAUf"
            ],
            "tags": [
                "tag-gfXTb",
                "tag-wqREq"
            ],
            "htmlMetas": []
        },
        "apiVersion": "content.halo.run/v1alpha1",
        "kind": "Post",
        "metadata": {
            "name": "971003431"
        }
    },
    "content": {
        "raw": "test md content\n# 这是一个测试\n内容如下",
        "content": "<p>test md content</p>\n<h1 id=\"_1\">这是一个测试</h1>\n<p>内容如下</p>",
        "rawType": "markdown"
    }
}

下面是两个API的调用结果。

调用 https://halo.musnow.top/apis/api.console.halo.run/v1alpha1/posts/971003431的结果:

{"type": "about:blank", "title": "Internal Server Error", "status": 500, "detail": "Something went wrong, please try again later.", "instance": "https://halo.musnow.top/apis/api.console.halo.run/v1alpha1/posts/971003431", "requestId": "a572f7df-484", "timestamp": "2024-01-31T10:58:03.647872446Z"}

调用 https://halo.musnow.top/apis/api.console.halo.run/v1alpha1/posts/971003431/content的结果:

{"spec": {"title": "【MySQL】deepin安装mysql的cpp开发包", "slug": "971003431", "releaseSnapshot": "b62881a3-887a-4344-ba09-6847c139f3e5", "headSnapshot": "c912e6b8-567a-4d1c-9687-db9267467efc", "baseSnapshot": "b62881a3-887a-4344-ba09-6847c139f3e5", "owner": "musnow", "template": "", "cover": "https://img.musnow.top/i/2023/04/64302610057ae.png", "deleted": false, "publish": true, "publishTime": "2023-08-02T07:52:14Z", "pinned": false, "allowComment": true, "visible": "PUBLIC", "priority": 0, "excerpt": {"autoGenerate": true, "raw": ""}, "categories": ["category-wsAUf"], "tags": ["tag-gfXTb", "tag-wqREq"], "htmlMetas": []}, "status": {"phase": "PUBLISHED", "conditions": [{"type": "PUBLISHED", "status": "TRUE", "lastTransitionTime": "2024-01-31T03:32:38.179473539Z", "message": "Post published successfully.", "reason": "Published"}, {"type": "DRAFT", "status": "TRUE", "lastTransitionTime": "2024-01-31T03:31:45.939853628Z", "message": "Drafted post successfully.", "reason": "DraftedSuccessfully"}], "permalink": "/posts/971003431", "excerpt": "在deepin下安装好mysql后,发现在c语言中没有<mysql.h>的头文件。 而根据ubuntu的办法直接按照mysql的开发包,会出现这种情况: ~/Desktop$ sudo apt-get install libmysqlclient-dev\n正在读取软件包列表… 完成\n正在分析软件包的", "inProgress": true, "contributors": ["musnow"], "lastModifyTime": "2024-01-31T03:32:37.370639323Z"}, "apiVersion": "content.halo.run/v1alpha1", "kind": "Post", "metadata": {"finalizers": ["post-protection"], "name": "971003431", "labels": {"content.halo.run/archive-year": "2023", "content.halo.run/archive-day": "02", "content.halo.run/archive-month": "08", "content.halo.run/published": "true", "content.halo.run/deleted": "false", "content.halo.run/owner": "musnow", "content.halo.run/visible": "PUBLIC"}, "annotations": {"content.halo.run/permalink-pattern": "/posts/{slug}", "checksum/config": "cf13720ac1ccd66900aac1faa743ec3884b96fea5795c694f7b5c539afb10d24", "content.halo.run/last-released-snapshot": "b62881a3-887a-4344-ba09-6847c139f3e5", "content.halo.run/preferred-editor": "vditor-mde"}, "version": 14, "creationTimestamp": "2024-01-31T03:31:45.908341035Z"}}

根据失败的requestId a572f7df-484在halo2日志中定位到如下报错(请求时传入的是整个data)

传入整个data时halo2中异常信息如下 ``` 2024-01-31T18:58:03.648+08:00 ERROR 7 --- [reactor-tcp-epoll-3] a.w.r.e.AbstractErrorWebExceptionHandler : [a572f7df-484] 500 Server Error for HTTP PUT "/apis/api.console.halo.run/v1alpha1/posts/971003431" org.springframework.dao.DuplicateKeyException: executeMany; SQL [INSERT INTO extensions (name, data, version) VALUES (?, ?, ?)]; Duplicate entry '/registry/content.halo.run/posts/971003431' for key 'extensions.PRIMARY' at org.springframework.r2dbc.connection.ConnectionFactoryUtils.convertR2dbcException(ConnectionFactoryUtils.java:245) ~[spring-r2dbc-6.1.1.jar:6.1.1] Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: Error has been observed at the following site(s): *__checkpoint ⇢ run.halo.app.security.InitializeRedirectionWebFilter [DefaultWebFilterChain] *__checkpoint ⇢ run.halo.app.security.authentication.login.UsernamePasswordLogoutHandler [DefaultWebFilterChain] *__checkpoint ⇢ run.halo.app.security.authentication.login.DelegatingLogoutPageGeneratingWebFilter [DefaultWebFilterChain] *__checkpoint ⇢ run.halo.app.security.authentication.login.UsernamePasswordAuthenticator [DefaultWebFilterChain] *__checkpoint ⇢ AuthorizationWebFilter [DefaultWebFilterChain] *__checkpoint ⇢ ExceptionTranslationWebFilter [DefaultWebFilterChain] *__checkpoint ⇢ LogoutWebFilter [DefaultWebFilterChain] *__checkpoint ⇢ ServerRequestCacheWebFilter [DefaultWebFilterChain] *__checkpoint ⇢ SecurityContextServerWebExchangeWebFilter [DefaultWebFilterChain] *__checkpoint ⇢ AnonymousAuthenticationWebFilter [DefaultWebFilterChain] *__checkpoint ⇢ AuthenticationWebFilter [DefaultWebFilterChain] *__checkpoint ⇢ AuthenticationWebFilter [DefaultWebFilterChain] *__checkpoint ⇢ ReactorContextWebFilter [DefaultWebFilterChain] *__checkpoint ⇢ CsrfWebFilter [DefaultWebFilterChain] *__checkpoint ⇢ CorsWebFilter [DefaultWebFilterChain] *__checkpoint ⇢ HttpHeaderWriterWebFilter [DefaultWebFilterChain] *__checkpoint ⇢ ServerWebExchangeReactorContextWebFilter [DefaultWebFilterChain] *__checkpoint ⇢ OrderedWebFilter [DefaultWebFilterChain] *__checkpoint ⇢ OrderedWebFilter [DefaultWebFilterChain] *__checkpoint ⇢ OrderedWebFilter [DefaultWebFilterChain] *__checkpoint ⇢ org.springframework.security.web.server.WebFilterChainProxy [DefaultWebFilterChain] *__checkpoint ⇢ HTTP PUT "/apis/api.console.halo.run/v1alpha1/posts/971003431" [ExceptionHandlingWebHandler] Original Stack Trace: at org.springframework.r2dbc.connection.ConnectionFactoryUtils.convertR2dbcException(ConnectionFactoryUtils.java:245) ~[spring-r2dbc-6.1.1.jar:6.1.1] at org.springframework.r2dbc.core.DefaultDatabaseClient.lambda$inConnectionMany$8(DefaultDatabaseClient.java:156) ~[spring-r2dbc-6.1.1.jar:6.1.1] at reactor.core.publisher.Flux.lambda$onErrorMap$28(Flux.java:7239) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.Flux.lambda$onErrorResume$29(Flux.java:7292) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:94) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxUsingWhen$UsingWhenSubscriber.deferredError(FluxUsingWhen.java:399) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxUsingWhen$RollbackInner.onComplete(FluxUsingWhen.java:476) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onComplete(Operators.java:2231) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxPeek$PeekSubscriber.onComplete(FluxPeek.java:260) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onComplete(Operators.java:2231) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.onComplete(MonoIgnoreThen.java:210) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.onComplete(MonoIgnoreThen.java:210) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.pool.SimpleDequePool.maybeRecycleAndDrain(SimpleDequePool.java:537) ~[reactor-pool-1.0.3.jar:1.0.3] at reactor.pool.SimpleDequePool$QueuePoolRecyclerInner.onComplete(SimpleDequePool.java:767) ~[reactor-pool-1.0.3.jar:1.0.3] at reactor.core.publisher.Operators.complete(Operators.java:137) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.MonoEmpty.subscribe(MonoEmpty.java:46) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.Mono.subscribe(Mono.java:4512) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.pool.SimpleDequePool$QueuePoolRecyclerMono.subscribe(SimpleDequePool.java:879) ~[reactor-pool-1.0.3.jar:1.0.3] at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.subscribeNext(MonoIgnoreThen.java:241) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.onComplete(MonoIgnoreThen.java:204) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxPeek$PeekSubscriber.onComplete(FluxPeek.java:260) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.Operators.complete(Operators.java:137) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.MonoEmpty.subscribe(MonoEmpty.java:46) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:76) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.subscribeNext(MonoIgnoreThen.java:264) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.MonoIgnoreThen.subscribe(MonoIgnoreThen.java:51) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.subscribeNext(MonoIgnoreThen.java:241) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.onComplete(MonoIgnoreThen.java:204) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.MonoIgnoreElements$IgnoreElementsSubscriber.onComplete(MonoIgnoreElements.java:89) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxHandleFuseable$HandleFuseableSubscriber.onComplete(FluxHandleFuseable.java:239) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.MonoSupplier$MonoSupplierSubscription.request(MonoSupplier.java:148) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxHandleFuseable$HandleFuseableSubscriber.request(FluxHandleFuseable.java:260) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.MonoIgnoreElements$IgnoreElementsSubscriber.onSubscribe(MonoIgnoreElements.java:72) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxHandleFuseable$HandleFuseableSubscriber.onSubscribe(FluxHandleFuseable.java:164) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.MonoSupplier.subscribe(MonoSupplier.java:48) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:76) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.subscribeNext(MonoIgnoreThen.java:264) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.MonoIgnoreThen.subscribe(MonoIgnoreThen.java:51) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:76) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.Mono.subscribe(Mono.java:4512) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:103) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.MonoIgnoreElements$IgnoreElementsSubscriber.onError(MonoIgnoreElements.java:84) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxMap$MapSubscriber.onError(FluxMap.java:134) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxFilter$FilterSubscriber.onError(FluxFilter.java:157) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxFilter$FilterConditionalSubscriber.onError(FluxFilter.java:291) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxMap$MapConditionalSubscriber.onError(FluxMap.java:265) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.Operators.error(Operators.java:198) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.MonoError.subscribe(MonoError.java:53) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.MonoDeferContextual.subscribe(MonoDeferContextual.java:55) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:76) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxUsingWhen$UsingWhenSubscriber.onError(FluxUsingWhen.java:365) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxFlatMap$FlatMapMain.checkTerminated(FluxFlatMap.java:846) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxFlatMap$FlatMapMain.drainLoop(FluxFlatMap.java:612) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxFlatMap$FlatMapMain.drain(FluxFlatMap.java:592) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxFlatMap$FlatMapMain.innerError(FluxFlatMap.java:867) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxFlatMap$FlatMapInner.onError(FluxFlatMap.java:994) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxHandleFuseable$HandleFuseableSubscriber.onNext(FluxHandleFuseable.java:201) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxHandleFuseable$HandleFuseableConditionalSubscriber.onNext(FluxHandleFuseable.java:505) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.onNext(FluxContextWrite.java:107) ~[reactor-core-3.6.0.jar:3.6.0] at io.asyncer.r2dbc.mysql.internal.util.DiscardOnCancelSubscriber.onNext(DiscardOnCancelSubscriber.java:66) ~[r2dbc-mysql-1.0.5.jar:1.0.5] at reactor.core.publisher.FluxWindowPredicate$WindowFlux.drainRegular(FluxWindowPredicate.java:670) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxWindowPredicate$WindowFlux.drain(FluxWindowPredicate.java:748) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxWindowPredicate$WindowFlux.onNext(FluxWindowPredicate.java:790) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxWindowPredicate$WindowPredicateMain.onNext(FluxWindowPredicate.java:268) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.MonoFlatMapMany$FlatMapManyInner.onNext(MonoFlatMapMany.java:250) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.onNext(FluxPeekFuseable.java:210) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.onNext(FluxContextWrite.java:107) ~[reactor-core-3.6.0.jar:3.6.0] at io.asyncer.r2dbc.mysql.internal.util.DiscardOnCancelSubscriber.onNext(DiscardOnCancelSubscriber.java:66) ~[r2dbc-mysql-1.0.5.jar:1.0.5] at reactor.core.publisher.FluxPeekFuseable$PeekConditionalSubscriber.onNext(FluxPeekFuseable.java:854) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxHandle$HandleConditionalSubscriber.onNext(FluxHandle.java:343) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxPeekFuseable$PeekConditionalSubscriber.onNext(FluxPeekFuseable.java:854) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.SinkManyEmitterProcessor.drain(SinkManyEmitterProcessor.java:476) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.SinkManyEmitterProcessor.tryEmitNext(SinkManyEmitterProcessor.java:273) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.SinkManySerialized.tryEmitNext(SinkManySerialized.java:100) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.InternalManySink.emitNext(InternalManySink.java:27) ~[reactor-core-3.6.0.jar:3.6.0] at io.asyncer.r2dbc.mysql.client.ReactorNettyClient$ResponseSink.next(ReactorNettyClient.java:383) ~[r2dbc-mysql-1.0.5.jar:1.0.5] at io.asyncer.r2dbc.mysql.client.ReactorNettyClient.lambda$new$0(ReactorNettyClient.java:121) ~[r2dbc-mysql-1.0.5.jar:1.0.5] at reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:185) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.netty.channel.FluxReceive.drainReceiver(FluxReceive.java:294) ~[reactor-netty-core-1.1.13.jar:1.1.13] at reactor.netty.channel.FluxReceive.onInboundNext(FluxReceive.java:403) ~[reactor-netty-core-1.1.13.jar:1.1.13] at reactor.netty.channel.ChannelOperations.onInboundNext(ChannelOperations.java:426) ~[reactor-netty-core-1.1.13.jar:1.1.13] at reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:114) ~[reactor-netty-core-1.1.13.jar:1.1.13] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444) ~[netty-transport-4.1.101.Final.jar:4.1.101.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) ~[netty-transport-4.1.101.Final.jar:4.1.101.Final] at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) ~[netty-transport-4.1.101.Final.jar:4.1.101.Final] at io.asyncer.r2dbc.mysql.client.MessageDuplexCodec.handleDecoded(MessageDuplexCodec.java:162) ~[r2dbc-mysql-1.0.5.jar:1.0.5] at io.asyncer.r2dbc.mysql.client.MessageDuplexCodec.channelRead(MessageDuplexCodec.java:73) ~[r2dbc-mysql-1.0.5.jar:1.0.5] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442) ~[netty-transport-4.1.101.Final.jar:4.1.101.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) ~[netty-transport-4.1.101.Final.jar:4.1.101.Final] at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) ~[netty-transport-4.1.101.Final.jar:4.1.101.Final] at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:346) ~[netty-codec-4.1.101.Final.jar:4.1.101.Final] at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:318) ~[netty-codec-4.1.101.Final.jar:4.1.101.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444) ~[netty-transport-4.1.101.Final.jar:4.1.101.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) ~[netty-transport-4.1.101.Final.jar:4.1.101.Final] at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) ~[netty-transport-4.1.101.Final.jar:4.1.101.Final] at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1475) ~[netty-handler-4.1.101.Final.jar:4.1.101.Final] at io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1338) ~[netty-handler-4.1.101.Final.jar:4.1.101.Final] at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1387) ~[netty-handler-4.1.101.Final.jar:4.1.101.Final] at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:529) ~[netty-codec-4.1.101.Final.jar:4.1.101.Final] at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:468) ~[netty-codec-4.1.101.Final.jar:4.1.101.Final] at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:290) ~[netty-codec-4.1.101.Final.jar:4.1.101.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444) ~[netty-transport-4.1.101.Final.jar:4.1.101.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) ~[netty-transport-4.1.101.Final.jar:4.1.101.Final] at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) ~[netty-transport-4.1.101.Final.jar:4.1.101.Final] at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410) ~[netty-transport-4.1.101.Final.jar:4.1.101.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:440) ~[netty-transport-4.1.101.Final.jar:4.1.101.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) ~[netty-transport-4.1.101.Final.jar:4.1.101.Final] at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919) ~[netty-transport-4.1.101.Final.jar:4.1.101.Final] at io.netty.channel.epoll.AbstractEpollStreamChannel$EpollStreamUnsafe.epollInReady(AbstractEpollStreamChannel.java:800) ~[netty-transport-classes-epoll-4.1.101.Final.jar:4.1.101.Final] at io.netty.channel.epoll.EpollEventLoop.processReady(EpollEventLoop.java:509) ~[netty-transport-classes-epoll-4.1.101.Final.jar:4.1.101.Final] at io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:407) ~[netty-transport-classes-epoll-4.1.101.Final.jar:4.1.101.Final] at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997) ~[netty-common-4.1.101.Final.jar:4.1.101.Final] at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[netty-common-4.1.101.Final.jar:4.1.101.Final] at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-common-4.1.101.Final.jar:4.1.101.Final] at java.base/java.lang.Thread.run(Unknown Source) ~[na:na] Caused by: io.r2dbc.spi.R2dbcDataIntegrityViolationException: Duplicate entry '/registry/content.halo.run/posts/971003431' for key 'extensions.PRIMARY' at io.asyncer.r2dbc.mysql.message.server.ErrorMessage.toException(ErrorMessage.java:121) ~[r2dbc-mysql-1.0.5.jar:1.0.5] at io.asyncer.r2dbc.mysql.message.server.ErrorMessage.toException(ErrorMessage.java:73) ~[r2dbc-mysql-1.0.5.jar:1.0.5] at io.asyncer.r2dbc.mysql.MySqlResult$MySqlMessage.exception(MySqlResult.java:178) ~[r2dbc-mysql-1.0.5.jar:1.0.5] at io.asyncer.r2dbc.mysql.MySqlResult.lambda$map$1(MySqlResult.java:92) ~[r2dbc-mysql-1.0.5.jar:1.0.5] at reactor.core.publisher.FluxHandleFuseable$HandleFuseableSubscriber.onNext(FluxHandleFuseable.java:179) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxHandleFuseable$HandleFuseableConditionalSubscriber.onNext(FluxHandleFuseable.java:505) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.onNext(FluxContextWrite.java:107) ~[reactor-core-3.6.0.jar:3.6.0] at io.asyncer.r2dbc.mysql.internal.util.DiscardOnCancelSubscriber.onNext(DiscardOnCancelSubscriber.java:66) ~[r2dbc-mysql-1.0.5.jar:1.0.5] at reactor.core.publisher.FluxWindowPredicate$WindowFlux.drainRegular(FluxWindowPredicate.java:670) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxWindowPredicate$WindowFlux.drain(FluxWindowPredicate.java:748) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxWindowPredicate$WindowFlux.onNext(FluxWindowPredicate.java:790) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxWindowPredicate$WindowPredicateMain.onNext(FluxWindowPredicate.java:268) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.MonoFlatMapMany$FlatMapManyInner.onNext(MonoFlatMapMany.java:250) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.onNext(FluxPeekFuseable.java:210) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.onNext(FluxContextWrite.java:107) ~[reactor-core-3.6.0.jar:3.6.0] at io.asyncer.r2dbc.mysql.internal.util.DiscardOnCancelSubscriber.onNext(DiscardOnCancelSubscriber.java:66) ~[r2dbc-mysql-1.0.5.jar:1.0.5] at reactor.core.publisher.FluxPeekFuseable$PeekConditionalSubscriber.onNext(FluxPeekFuseable.java:854) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxHandle$HandleConditionalSubscriber.onNext(FluxHandle.java:343) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxPeekFuseable$PeekConditionalSubscriber.onNext(FluxPeekFuseable.java:854) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.SinkManyEmitterProcessor.drain(SinkManyEmitterProcessor.java:476) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.SinkManyEmitterProcessor.tryEmitNext(SinkManyEmitterProcessor.java:273) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.SinkManySerialized.tryEmitNext(SinkManySerialized.java:100) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.InternalManySink.emitNext(InternalManySink.java:27) ~[reactor-core-3.6.0.jar:3.6.0] at io.asyncer.r2dbc.mysql.client.ReactorNettyClient$ResponseSink.next(ReactorNettyClient.java:383) ~[r2dbc-mysql-1.0.5.jar:1.0.5] at io.asyncer.r2dbc.mysql.client.ReactorNettyClient.lambda$new$0(ReactorNettyClient.java:121) ~[r2dbc-mysql-1.0.5.jar:1.0.5] at reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:185) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.netty.channel.FluxReceive.drainReceiver(FluxReceive.java:294) ~[reactor-netty-core-1.1.13.jar:1.1.13] at reactor.netty.channel.FluxReceive.onInboundNext(FluxReceive.java:403) ~[reactor-netty-core-1.1.13.jar:1.1.13] at reactor.netty.channel.ChannelOperations.onInboundNext(ChannelOperations.java:426) ~[reactor-netty-core-1.1.13.jar:1.1.13] at reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:114) ~[reactor-netty-core-1.1.13.jar:1.1.13] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444) ~[netty-transport-4.1.101.Final.jar:4.1.101.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) ~[netty-transport-4.1.101.Final.jar:4.1.101.Final] at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) ~[netty-transport-4.1.101.Final.jar:4.1.101.Final] at io.asyncer.r2dbc.mysql.client.MessageDuplexCodec.handleDecoded(MessageDuplexCodec.java:162) ~[r2dbc-mysql-1.0.5.jar:1.0.5] at io.asyncer.r2dbc.mysql.client.MessageDuplexCodec.channelRead(MessageDuplexCodec.java:73) ~[r2dbc-mysql-1.0.5.jar:1.0.5] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442) ~[netty-transport-4.1.101.Final.jar:4.1.101.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) ~[netty-transport-4.1.101.Final.jar:4.1.101.Final] at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) ~[netty-transport-4.1.101.Final.jar:4.1.101.Final] at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:346) ~[netty-codec-4.1.101.Final.jar:4.1.101.Final] at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:318) ~[netty-codec-4.1.101.Final.jar:4.1.101.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444) ~[netty-transport-4.1.101.Final.jar:4.1.101.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) ~[netty-transport-4.1.101.Final.jar:4.1.101.Final] at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) ~[netty-transport-4.1.101.Final.jar:4.1.101.Final] at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1475) ~[netty-handler-4.1.101.Final.jar:4.1.101.Final] at io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1338) ~[netty-handler-4.1.101.Final.jar:4.1.101.Final] at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1387) ~[netty-handler-4.1.101.Final.jar:4.1.101.Final] at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:529) ~[netty-codec-4.1.101.Final.jar:4.1.101.Final] at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:468) ~[netty-codec-4.1.101.Final.jar:4.1.101.Final] at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:290) ~[netty-codec-4.1.101.Final.jar:4.1.101.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444) ~[netty-transport-4.1.101.Final.jar:4.1.101.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) ~[netty-transport-4.1.101.Final.jar:4.1.101.Final] at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) ~[netty-transport-4.1.101.Final.jar:4.1.101.Final] at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410) ~[netty-transport-4.1.101.Final.jar:4.1.101.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:440) ~[netty-transport-4.1.101.Final.jar:4.1.101.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) ~[netty-transport-4.1.101.Final.jar:4.1.101.Final] at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919) ~[netty-transport-4.1.101.Final.jar:4.1.101.Final] at io.netty.channel.epoll.AbstractEpollStreamChannel$EpollStreamUnsafe.epollInReady(AbstractEpollStreamChannel.java:800) ~[netty-transport-classes-epoll-4.1.101.Final.jar:4.1.101.Final] at io.netty.channel.epoll.EpollEventLoop.processReady(EpollEventLoop.java:509) ~[netty-transport-classes-epoll-4.1.101.Final.jar:4.1.101.Final] at io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:407) ~[netty-transport-classes-epoll-4.1.101.Final.jar:4.1.101.Final] at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997) ~[netty-common-4.1.101.Final.jar:4.1.101.Final] at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[netty-common-4.1.101.Final.jar:4.1.101.Final] at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-common-4.1.101.Final.jar:4.1.101.Final] at java.base/java.lang.Thread.run(Unknown Source) ~[na:na] ```

如果依照vscode插件,只传入data["posts"]部分,异常信息会不同。

只传入data["posts"]部分,halo2中异常信息如下 ``` 2024-01-31T19:02:27.209+08:00 ERROR 7 --- [reactor-http-epoll-4] a.w.r.e.AbstractErrorWebExceptionHandler : [8570d9da-503] 500 Server Error for HTTP PUT "/apis/api.console.halo.run/v1alpha1/posts/971003431" java.lang.NullPointerException: Cannot invoke "run.halo.app.core.extension.content.Post.getSpec()" because "post" is null at run.halo.app.content.impl.PostServiceImpl.updatePost(PostServiceImpl.java:234) ~[classes/:2.11.3] Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: Error has been observed at the following site(s): *__checkpoint ⇢ run.halo.app.security.InitializeRedirectionWebFilter [DefaultWebFilterChain] *__checkpoint ⇢ run.halo.app.security.authentication.login.UsernamePasswordLogoutHandler [DefaultWebFilterChain] *__checkpoint ⇢ run.halo.app.security.authentication.login.DelegatingLogoutPageGeneratingWebFilter [DefaultWebFilterChain] *__checkpoint ⇢ run.halo.app.security.authentication.login.UsernamePasswordAuthenticator [DefaultWebFilterChain] *__checkpoint ⇢ AuthorizationWebFilter [DefaultWebFilterChain] *__checkpoint ⇢ ExceptionTranslationWebFilter [DefaultWebFilterChain] *__checkpoint ⇢ LogoutWebFilter [DefaultWebFilterChain] *__checkpoint ⇢ ServerRequestCacheWebFilter [DefaultWebFilterChain] *__checkpoint ⇢ SecurityContextServerWebExchangeWebFilter [DefaultWebFilterChain] *__checkpoint ⇢ AnonymousAuthenticationWebFilter [DefaultWebFilterChain] *__checkpoint ⇢ AuthenticationWebFilter [DefaultWebFilterChain] *__checkpoint ⇢ AuthenticationWebFilter [DefaultWebFilterChain] *__checkpoint ⇢ ReactorContextWebFilter [DefaultWebFilterChain] *__checkpoint ⇢ CsrfWebFilter [DefaultWebFilterChain] *__checkpoint ⇢ CorsWebFilter [DefaultWebFilterChain] *__checkpoint ⇢ HttpHeaderWriterWebFilter [DefaultWebFilterChain] *__checkpoint ⇢ ServerWebExchangeReactorContextWebFilter [DefaultWebFilterChain] *__checkpoint ⇢ OrderedWebFilter [DefaultWebFilterChain] *__checkpoint ⇢ OrderedWebFilter [DefaultWebFilterChain] *__checkpoint ⇢ OrderedWebFilter [DefaultWebFilterChain] *__checkpoint ⇢ org.springframework.security.web.server.WebFilterChainProxy [DefaultWebFilterChain] *__checkpoint ⇢ HTTP PUT "/apis/api.console.halo.run/v1alpha1/posts/971003431" [ExceptionHandlingWebHandler] Original Stack Trace: at run.halo.app.content.impl.PostServiceImpl.updatePost(PostServiceImpl.java:234) ~[classes/:2.11.3] at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:132) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:158) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.onNext(FluxContextWrite.java:107) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxMapFuseable$MapFuseableConditionalSubscriber.onNext(FluxMapFuseable.java:299) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxFilterFuseable$FilterFuseableConditionalSubscriber.onNext(FluxFilterFuseable.java:337) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.Operators$BaseFluxToMonoOperator.completePossiblyEmpty(Operators.java:2097) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.MonoCollect$CollectSubscriber.onComplete(MonoCollect.java:145) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:144) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxPeek$PeekSubscriber.onComplete(FluxPeek.java:260) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:144) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.netty.channel.FluxReceive.terminateReceiver(FluxReceive.java:483) ~[reactor-netty-core-1.1.13.jar:1.1.13] at reactor.netty.channel.FluxReceive.drainReceiver(FluxReceive.java:275) ~[reactor-netty-core-1.1.13.jar:1.1.13] at reactor.netty.channel.FluxReceive.request(FluxReceive.java:133) ~[reactor-netty-core-1.1.13.jar:1.1.13] at reactor.core.publisher.FluxMap$MapSubscriber.request(FluxMap.java:164) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxPeek$PeekSubscriber.request(FluxPeek.java:138) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxMap$MapSubscriber.request(FluxMap.java:164) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.Operators$BaseFluxToMonoOperator.request(Operators.java:2067) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxFilterFuseable$FilterFuseableConditionalSubscriber.request(FluxFilterFuseable.java:411) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxMapFuseable$MapFuseableConditionalSubscriber.request(FluxMapFuseable.java:360) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.request(FluxContextWrite.java:136) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.MonoFlatMap$FlatMapMain.request(MonoFlatMap.java:194) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.set(Operators.java:2367) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onSubscribe(FluxOnErrorResume.java:74) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.MonoFlatMap$FlatMapMain.onSubscribe(MonoFlatMap.java:117) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.onSubscribe(FluxContextWrite.java:101) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxMapFuseable$MapFuseableConditionalSubscriber.onSubscribe(FluxMapFuseable.java:265) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxFilterFuseable$FilterFuseableConditionalSubscriber.onSubscribe(FluxFilterFuseable.java:305) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.Operators$BaseFluxToMonoOperator.onSubscribe(Operators.java:2051) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxMap$MapSubscriber.onSubscribe(FluxMap.java:92) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxPeek$PeekSubscriber.onSubscribe(FluxPeek.java:171) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.core.publisher.FluxMap$MapSubscriber.onSubscribe(FluxMap.java:92) ~[reactor-core-3.6.0.jar:3.6.0] at reactor.netty.channel.FluxReceive.startReceiver(FluxReceive.java:172) ~[reactor-netty-core-1.1.13.jar:1.1.13] at reactor.netty.channel.FluxReceive.lambda$subscribe$2(FluxReceive.java:150) ~[reactor-netty-core-1.1.13.jar:1.1.13] at io.netty.util.concurrent.AbstractEventExecutor.runTask(AbstractEventExecutor.java:173) ~[netty-common-4.1.101.Final.jar:4.1.101.Final] at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:166) ~[netty-common-4.1.101.Final.jar:4.1.101.Final] at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:470) ~[netty-common-4.1.101.Final.jar:4.1.101.Final] at io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:413) ~[netty-transport-classes-epoll-4.1.101.Final.jar:4.1.101.Final] at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997) ~[netty-common-4.1.101.Final.jar:4.1.101.Final] at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[netty-common-4.1.101.Final.jar:4.1.101.Final] at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-common-4.1.101.Final.jar:4.1.101.Final] at java.base/java.lang.Thread.run(Unknown Source) ~[na:na] ```
musnows commented 5 months ago

我又重新看了看vscode插件的逻辑 https://github.com/halo-sigs/vscode-extension-halo/blob/3f2845b4a1e5b45b4dc0d2f227aada4604fe324b/src/service/index.ts#L40-L57 似乎如果需要更新文章,是根据name重新获取一个完整的posts信息再去PUT请求接口的,我的data载荷中post部分是否缺少字段?

在我这边尝试请求这两个接口,其中 /apis/api.console.halo.run/v1alpha1/posts/971003431/head-content 接口有内容,但是/apis/api.console.halo.run/v1alpha1/posts/971003431 会404

ruibaby commented 5 months ago

是根据name重新获取一个完整的posts信息再去PUT请求接口的,我的data载荷中post部分是否缺少字段?

如果是更新文章,建议先根据 metadata.name 获取完整的文章信息,然后再更新,因为服务内部在创建文章之后还有可能会去更新或者设置其他字段。

但是/apis/api.console.halo.run/v1alpha1/posts/971003431 会404

/apis/content.halo.run/v1alpha1/posts/971003431,不是 /apis/api.console.halo.run/v1alpha1/posts/971003431

musnows commented 5 months ago

是根据name重新获取一个完整的posts信息再去PUT请求接口的,我的data载荷中post部分是否缺少字段?

如果是更新文章,建议先根据 metadata.name 获取完整的文章信息,然后再更新,因为服务内部在创建文章之后还有可能会去更新或者设置其他字段。

但是/apis/api.console.halo.run/v1alpha1/posts/971003431 会404

/apis/content.halo.run/v1alpha1/posts/971003431,不是 /apis/api.console.halo.run/v1alpha1/posts/971003431

感谢大佬指正!!!!我发现我update函数里面的posts_url的api链接也写错了😭我实在是太不细心了,向诸位大佬道歉

现在我修改了代码,data['post']data['content']部分都是直接调用/apis/content.halo.run/v1alpha1/posts/971003431/apis/api.console.halo.run/v1alpha1/posts/971003431/head-content接口返回的内容。

下面的代码中,data['post']部分只修改了文章的['spec']['title'],此时PUT请求/apis/content.halo.run/v1alpha1/posts/971003431 成功。

# 文章id
slug = "971003431"
posts_url = f"/apis/content.halo.run/v1alpha1/posts/{slug}"
# 获取文章post的内容
data = {}
data["post"] = requests.get(url=BASE_URL + posts_url,
                            headers=BASE_HEADER).json()
# 修改文章标题
data["post"]["spec"]["title"] = "这是一个用于更新测试的新标题"

# 调用更新api
ret1 = requests.put(url=BASE_URL + posts_url,
                    json=data["post"],
                    headers=BASE_HEADER)  # 这里要用json来传data
print(json.dumps(ret1.json(), ensure_ascii=False))

API请求结果如下

{"spec": {"title": "这是一个用于更新测试的新标题", "slug": "971003431", "releaseSnapshot": "b62881a3-887a-4344-ba09-6847c139f3e5", "headSnapshot": "c912e6b8-567a-4d1c-9687-db9267467efc", "baseSnapshot": "b62881a3-887a-4344-ba09-6847c139f3e5", "owner": "musnow", "template": "", "cover": "https://img.musnow.top/i/2023/04/64302610057ae.png", "deleted": false, "publish": true, "publishTime": "2023-08-02T07:52:14Z", "pinned": false, "allowComment": true, "visible": "PUBLIC", "priority": 0, "excerpt": {"autoGenerate": true, "raw": ""}, "categories": ["category-wsAUf"], "tags": ["tag-gfXTb", "tag-wqREq"], "htmlMetas": []}, "status": {"phase": "PUBLISHED", "conditions": [{"type": "PUBLISHED", "status": "TRUE", "lastTransitionTime": "2024-01-31T03:32:38.179473539Z", "message": "Post published successfully.", "reason": "Published"}, {"type": "DRAFT", "status": "TRUE", "lastTransitionTime": "2024-01-31T03:31:45.939853628Z", "message": "Drafted post successfully.", "reason": "DraftedSuccessfully"}], "permalink": "/posts/971003431", "excerpt": "在deepin下安装好mysql后,发现在c语言中没 有<mysql.h>的头文件。 而根据ubuntu的办法直接按照mysql的开发包,会出现这种情况: ~/Desktop$ sudo apt-get install libmysqlclient-dev\n正在读取软件包列表… 完成\n正在分析软件包的", "inProgress": true, "contributors": ["musnow"], "lastModifyTime": "2024-01-31T03:32:37.370639323Z"}, "apiVersion": "content.halo.run/v1alpha1", "kind": "Post", "metadata": {"finalizers": ["post-protection"], "name": "971003431", "labels": {"content.halo.run/archive-year": "2023", "content.halo.run/archive-day": "02", "content.halo.run/archive-month": "08", "content.halo.run/published": "true", "content.halo.run/deleted": "false", "content.halo.run/owner": "musnow", "content.halo.run/visible": "PUBLIC"}, "annotations": {"content.halo.run/permalink-pattern": "/posts/{slug}", "checksum/config": "cf13720ac1ccd66900aac1faa743ec3884b96fea5795c694f7b5c539afb10d24", "content.halo.run/last-released-snapshot": "b62881a3-887a-4344-ba09-6847c139f3e5", "content.halo.run/preferred-editor": "vditor-mde"}, "version": 18, "creationTimestamp": "2024-01-31T03:31:45.908341035Z"}}

标题成功更新

image

在这里记录一个自己遇到的小问题,即应该GET请求后立马在代码中用GET请求的返回值,修改相关信息后PUT,不应该用历史GET结果来模拟请求,否则会导致后台报错:org.springframework.dao.OptimisticLockingFailureException: Failed to update table [extensions]; Version does not match for row with Id [/registry/content.halo.run/posts/971003431]

再次感谢大佬们的帮助,为自己的粗心看错API地址道歉。