管理用API HTTP Status 405 – Method Not Allowed

下記ページ
管理用APIの使い方

を参考に管理用APIをテストしているのですが、管理用APIの実行がうまく行きません。
(Fessバージョンは 14.2 で環境構築しています。)

「スケジューラ」のところに書かれている

以下のコマンドでスケジューラに登録されているジョブの一覧を取得します。

$ curl -H “Authorization: access_token” -XGET “http://localhost:8080/api/admin/scheduler/settings

は実行後にジョブ一覧が正しく返ってきたのですが、

「クローラ設定」のところの

次にPUTメソッドで上記のJSONを管理用APIでFessに送信します。
アクセストークンはAutorizationリクエストヘッダーで指定します。curlコマンド内の access_token は管理画面で取得したアクセストークンに置き換えて実行してください。

$ curl -H “Authorization: access_token” -XPUT “http://localhost:8080/api/admin/webconfig/setting” -d ‘{“name”:“Fess : https://fess.codelibs.org/",“description”:"Enterprise Search Server: Fess”,“urls”:“https://fess.codelibs.org/",“included_urls”:“https://fess.codelibs.org/.*”,“user_agent”:“Mozilla/5.0”,“num_of_thread”:1,“interval_time”:10000,“boost”:1,“available”:true,"sort_order”:0}’

を実行しても、
「HTTP Status 405 – Method Not Allowed」
というページのソースが返ってきてしまい、処理実行できませんでした。
(curl -L オプションで結果を確認しました。)

他に、-XDELETE を試そうとしてもやはり「HTTP Status 405 – Method Not Allowed」となってしまいます。

ジョブ一覧取得の際、アクセストークンをわざとデタラメにすると
{“response”:{“message”:“Unauthorized request.”,“version”:“14.2”,“status”:3}}
という結果になったので、アクセストークンを間違えていることはないと思っています。

クローラ設定で「HTTP Status 405 – Method Not Allowed」となってしまう原因
がどこにあるか何か推測できますでしょうか。

debugレベルにして、fess.logを確認してみるとかが良いと思います。

ご返信ありがとうございます。

debugモードにしてクロール設定の追加コマンド(↓)を再実行してみました。

curl -L -H “Authorization: (アクセストークン)” -XPUT “localhost/api/admin/scheduler/setting” -d ‘{“name”:“Fess : https://fess.codelibs.org/",“description”:"Enterprise Search Server: Fess”,“urls”:“https://fess.codelibs.org/",“included_urls”:“https://fess.codelibs.org/.*”,“user_agent”:“Mozilla/5.0”,“num_of_thread”:1,“interval_time”:10000,“boost”:1,“available”:true,"sort_order”:0}’

結果、fess.log に「400 Bad Request」が出ていることが確認できました。

サンプル通りに実行しているつもりですが、どこがうまく行っていないかわかりますでしょうか。

(最初に書くのを忘れていましたが、Windows Server 2016 でfess を動かしていて、
curl を別途インストール(zip解凍)し、そこでcurlコマンド発行しています。)

=== fess.log ======================================
2022-10-22 14:57:16,752 [http-nio-80-exec-3] DEBUG * * * * * * * * * * {BEGIN}: /api/admin/scheduler/setting
requestClass=org.apache.catalina.connector.RequestFacade ; sessionId=null
; url=http://localhost/api/admin/scheduler/setting
; method=PUT ; protocol=HTTP/1.1 ; scheme=http ; secure=false ; remoteAddr=127.0.0.1 ; remoteHost=127.0.0.1
; characterEncoding=UTF-8 ; contentLength=255 ; contentType=application/x-www-form-urlencoded ; locale=ja_JP ; locales=ja_JP
[header] accept=/
[header] authorization=(アクセストークン)
[header] content-length=255
[header] content-type=application/x-www-form-urlencoded
[header] host=localhost
[header] user-agent=curl/7.85.0
2022-10-22 14:57:16,792 [http-nio-80-exec-3] DEBUG …Routing to action: name=api_admin_scheduler_apiAdminSchedulerAction params={setting}
2022-10-22 14:57:16,794 [http-nio-80-exec-3] DEBUG by the mapping path: /api/admin/scheduler/setting
2022-10-22 14:57:16,796 [http-nio-80-exec-3] DEBUG …Saving user locale to session: ja_JP
2022-10-22 14:57:16,797 [http-nio-80-exec-3] DEBUG #flow …Parsing JSON from request body:
‘{name:Fess : https://fess.codelibs.org/,description:Enterprise Search Server: Fess,urls:https://fess.codelibs.org/,included_urls:https://fess.codelibs.org/.*,user_agent:Mozilla/5.0,num_of_thread:1,interval_time:10000,boost:1,available:true,sort_order:0}’
2022-10-22 14:57:16,800 [http-nio-80-exec-3] INFO
//////////////////////////////////////////_/
…Sending error as ‘400 Bad Request’ manually #7a93e73d
requestClass=org.apache.catalina.connector.RequestFacade ; sessionId=null
; url=http://localhost/api/admin/scheduler/setting
; method=PUT ; protocol=HTTP/1.1 ; scheme=http ; secure=false ; remoteAddr=127.0.0.1 ; remoteHost=127.0.0.1
; characterEncoding=UTF-8 ; contentLength=255 ; contentType=application/x-www-form-urlencoded ; locale=ja_JP ; locales=ja_JP
[header] accept=/
[header] authorization=(アクセストークン)
[header] content-length=255
[header] content-type=application/x-www-form-urlencoded
[header] host=localhost
[header] user-agent=curl/7.85.0
[request] VirtualHostValue=
[request] api_admin_scheduler_apiAdminSchedulerAction_setting_Form=VirtualForm:{formMeta:{api_admin_scheduler_apiAdminSchedulerAction_setting_Form, org.codelibs.fess.app.web.api.admin.scheduler.CreateBody, props=12}, realForm=null}@225e7baf
[request] lastaflute.action.ACTION_RUMTIME=runtime:{/api/admin/scheduler/setting, public JsonResponse ApiAdminSchedulerAction@put$setting(CreateBody), pathParam:{{}}}
[request] lastaflute.action.REQUEST_BODY=wholeShow:‘{name:Fess : https://fess.codelibs.org/,description:Enterprise Search Server: Fess,urls:https://fess.codelibs.org/,included_urls:https://fess.codelibs.org/.*,user_agent:Mozilla/5.0,num_of_thread:1,interval_time:10000,boost:1,available:true,sort_order:0}’
[request] lastaflute.action.USER_LOCALE=ja_JP
[request] lastaflute.config.ACTION_EXECUTE=execute:{public JsonResponse ApiAdminSchedulerAction@put$setting(CreateBody), urlPattern:{setting, ^setting$}}@3c942846
[session] lastaflute.action.USER_LOCALE=ja_JP
Exception: org.lastaflute.web.exception.RequestJsonParseFailureException
Message:
/- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cannot parse json on the request body.

[JsonBody Parse Failure]
runtime:{/api/admin/scheduler/setting, public JsonResponse ApiAdminSchedulerAction@put$setting(CreateBody), pathParam:{{}}}
VirtualForm:{formMeta:{api_admin_scheduler_apiAdminSchedulerAction_setting_Form, org.codelibs.fess.app.web.api.admin.scheduler.CreateBody, props=12}, realForm=null}@225e7baf
‘{name:Fess : https://fess.codelibs.org/,description:Enterprise Search Server: Fess,urls:https://fess.codelibs.org/,included_urls:https://fess.codelibs.org/.*,user_agent:Mozilla/5.0,num_of_thread:1,interval_time:10000,boost:1,available:true,sort_order:0}’

                  • -/
                    Stack Traces:
                    at org.lastaflute.web.ruts.process.formcoins.FormCoinsHelper.throwRequestJsonParseFailureException(FormCoinsHelper.java:644)
                    at org.lastaflute.web.ruts.process.formcoins.FormCoinsHelper.throwJsonBodyParseFailureException(FormCoinsHelper.java:200)
                    at org.lastaflute.web.ruts.process.ActionFormMapper.throwJsonBodyParseFailureException(ActionFormMapper.java:306)
                    at org.lastaflute.web.ruts.process.ActionFormMapper.mappingJsonBody(ActionFormMapper.java:301)
                    at org.lastaflute.web.ruts.process.ActionFormMapper.handleJsonBody(ActionFormMapper.java:249)
                    at org.lastaflute.web.ruts.process.ActionFormMapper.populateParameter(ActionFormMapper.java:149)
                    at org.lastaflute.web.ruts.ActionRequestProcessor.populateParameter(ActionRequestProcessor.java:221)
                    at org.lastaflute.web.ruts.ActionRequestProcessor.fire(ActionRequestProcessor.java:179)
                    at org.lastaflute.web.ruts.ActionRequestProcessor.process(ActionRequestProcessor.java:114)
                    at org.lastaflute.web.servlet.filter.RequestRoutingFilter.processAction(RequestRoutingFilter.java:289)
                    at org.lastaflute.web.servlet.filter.RequestRoutingFilter.routingToAction(RequestRoutingFilter.java:227)

                    Caused by: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 2 path $
                    at com.google.gson.internal.bind.LaReflectiveTypeAdapterFactory$ReflextiveAdapter.read(LaReflectiveTypeAdapterFactory.java:282)
                    at com.google.gson.Gson.fromJson(Gson.java:991)
                    at com.google.gson.Gson.fromJson(Gson.java:956)
                    at com.google.gson.Gson.fromJson(Gson.java:905)

                    Caused by: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 2 path $
                    at com.google.gson.stream.JsonReader.beginObject(JsonReader.java:385)
                    at com.google.gson.internal.bind.LaReflectiveTypeAdapterFactory$ReflextiveAdapter.read(LaReflectiveTypeAdapterFactory.java:271)
                    at com.google.gson.Gson.fromJson(Gson.java:991)
                    at com.google.gson.Gson.fromJson(Gson.java:956)

                    //////////
                    2022-10-22 14:57:16,801 [http-nio-80-exec-3] DEBUG
                    responseClass=org.apache.catalina.connector.ResponseFacade ; committed=true
                    ; httpStatus=400 ; contentType=null ; locale=ja_JP
                    [header] Set-Cookie=JSESSIONID=7E702335313E203825BD227DBB79E670; Path=/; HttpOnly
                    [request] VirtualHostValue=
                    [request] api_admin_scheduler_apiAdminSchedulerAction_setting_Form=VirtualForm:{formMeta:{api_admin_scheduler_apiAdminSchedulerAction_setting_Form, org.codelibs.fess.app.web.api.admin.scheduler.CreateBody, props=12}, realForm=null}@225e7baf
                    [request] lastaflute.action.ACTION_RUMTIME=runtime:{/api/admin/scheduler/setting, public JsonResponse ApiAdminSchedulerAction@put$setting(CreateBody), pathParam:{{}}}
                    [request] lastaflute.action.USER_LOCALE=ja_JP
                    [request] lastaflute.config.ACTION_EXECUTE=execute:{public JsonResponse ApiAdminSchedulerAction@put$setting(CreateBody), urlPattern:{setting, ^setting$}}@3c942846
                    [session] lastaflute.action.USER_LOCALE=ja_JP
                    • {END}: /api/admin/scheduler/setting [00m00s049ms]
                      *400 Bad Request, read the message for the detail

2022-10-22 14:57:16,807 [http-nio-80-exec-2] DEBUG * * * * * * * * * * {BEGIN}: /error/badrequest/
requestClass=org.apache.catalina.connector.RequestFacade ; sessionId=null
; url=http://localhost/error/badrequest/
; method=PUT ; protocol=HTTP/1.1 ; scheme=http ; secure=false ; remoteAddr=127.0.0.1 ; remoteHost=127.0.0.1
; characterEncoding=UTF-8 ; contentLength=-1 ; contentType=null ; locale=ja_JP ; locales=ja_JP
[header] accept=/
[header] authorization=アクセストークン
[header] host=localhost
[header] user-agent=curl/7.85.0
2022-10-22 14:57:16,809 [http-nio-80-exec-2] DEBUG
/= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = *No routing action:
e.g. expected actions for /error/badrequest/
web.error.ErrorBadrequestAction@index()
web.error.ErrorAction@badrequest()
web.error.badrequest.ErrorBadrequestAction@index()
(and so on…)
= = = = = = = = = =/
2022-10-22 14:57:16,811 [http-nio-80-exec-2] DEBUG
responseClass=org.apache.catalina.connector.ResponseFacade ; committed=true
; httpStatus=405 ; contentType=null ; locale=ja_JP
[header] Allow=OPTIONS, GET, HEAD, POST
[request] VirtualHostValue=

                    • {END}: /error/badrequest/ [00m00s004ms]

=========================================

よろしくお願いいたします。

「curl windows エスケープ」などでググって確認してもらうのが良いと思いますが、Windowsでcurlコマンドを利用する場合は"をエスケープが必要になるので、JSON部分は適切にエスケープなどすると良いと思います。Fessとしては、壊れたJSONを送られたので、エラーになったという感じだと思います。

ありがとうございます。
" のエスケープでパラメータがうまく渡るようになりました。

ただ、クロール設定追加コマンド(PUT)では 405 のエラーが消えたのですが、
インデックスの削除を試そうとしたDELTEコマンドの場合 、エスケープしても「HTTP Status 405 – Method Not Allowed」が直りませんでした。

fess.log に出ている

2022-10-24 09:04:14,192 [http-nio-80-exec-8] DEBUG
responseClass=org.apache.catalina.connector.ResponseFacade ; committed=true
; httpStatus=405 ; contentType=null ; locale=ja_JP
[header] Allow=OPTIONS, GET, HEAD, POST
[request] VirtualHostValue=

が気になるのですが、「DELETE」の場合「PUT」と違って他の設定が必要になったりするでしょうか。

何度もすみませんが、ご返信いただければ幸いです。

実行コマンド
curl -L -H “Authorization: アクセストークン” -XDELETE “http://ホスト/api/admin/searchlist/query” -d ‘{"q":"キーワード"}’

デバッグログ
2022-10-24 09:04:14,118 [http-nio-80-exec-7] DEBUG * * * * * * * * * * {BEGIN}: /api/admin/searchlist/query
requestClass=org.apache.catalina.connector.RequestFacade ; sessionId=null
; url=http://ホスト/api/admin/searchlist/query
; method=DELETE ; protocol=HTTP/1.1 ; scheme=http ; secure=false ; remoteAddr=0:0:0:0:0:0:0:1 ; remoteHost=0:0:0:0:0:0:0:1
; characterEncoding=UTF-8 ; contentLength=23 ; contentType=application/x-www-form-urlencoded ; locale=ja_JP ; locales=ja_JP
[header] accept=/
[header] authorization=アクセストークン
[header] content-length=23
[header] content-type=application/x-www-form-urlencoded
[header] host=ホスト
[header] user-agent=curl/7.85.0
2022-10-24 09:04:14,164 [http-nio-80-exec-7] DEBUG …Routing to action: name=api_admin_searchlist_apiAdminSearchlistAction params={query}
2022-10-24 09:04:14,166 [http-nio-80-exec-7] DEBUG by the mapping path: /api/admin/searchlist/query
2022-10-24 09:04:14,169 [http-nio-80-exec-7] DEBUG …Saving user locale to session: ja_JP
2022-10-24 09:04:14,172 [http-nio-80-exec-7] DEBUG #flow …Parsing JSON from request body:
‘{“q”:“キーワード”}’
2022-10-24 09:04:14,175 [http-nio-80-exec-7] INFO
//////////////////////////////////////////_/
…Sending error as ‘400 Bad Request’ manually #13c1897a
requestClass=org.apache.catalina.connector.RequestFacade ; sessionId=null
; url=http://ホスト/api/admin/searchlist/query
; method=DELETE ; protocol=HTTP/1.1 ; scheme=http ; secure=false ; remoteAddr=0:0:0:0:0:0:0:1 ; remoteHost=0:0:0:0:0:0:0:1
; characterEncoding=UTF-8 ; contentLength=23 ; contentType=application/x-www-form-urlencoded ; locale=ja_JP ; locales=ja_JP
[header] accept=/
[header] authorization=アクセストークン
[header] content-length=23
[header] content-type=application/x-www-form-urlencoded
[header] host=ホスト
[header] user-agent=curl/7.85.0
[request] VirtualHostValue=
[request] api_admin_searchlist_apiAdminSearchlistAction_query_Form=VirtualForm:{formMeta:{api_admin_searchlist_apiAdminSearchlistAction_query_Form, org.codelibs.fess.app.web.api.admin.searchlist.SearchBody, props=24}, realForm=null}@1c75fb26
[request] lastaflute.action.ACTION_RUMTIME=runtime:{/api/admin/searchlist/query, public JsonResponse ApiAdminSearchlistAction@delete$query(SearchBody), pathParam:{{}}}
[request] lastaflute.action.REQUEST_BODY=wholeShow:‘{“q”:“キーワード”}’
[request] lastaflute.action.USER_LOCALE=ja_JP
[request] lastaflute.config.ACTION_EXECUTE=execute:{public JsonResponse ApiAdminSearchlistAction@delete$query(SearchBody), urlPattern:{query, ^query$}}@4adcd625
[session] lastaflute.action.USER_LOCALE=ja_JP
Exception: org.lastaflute.web.exception.RequestJsonParseFailureException
Message:
/- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cannot parse json on the request body.

[JsonBody Parse Failure]
runtime:{/api/admin/searchlist/query, public JsonResponse ApiAdminSearchlistAction@delete$query(SearchBody), pathParam:{{}}}
VirtualForm:{formMeta:{api_admin_searchlist_apiAdminSearchlistAction_query_Form, org.codelibs.fess.app.web.api.admin.searchlist.SearchBody, props=24}, realForm=null}@1c75fb26
‘{“q”:“キーワード”}’

                  • -/
                    Stack Traces:
                    at org.lastaflute.web.ruts.process.formcoins.FormCoinsHelper.throwRequestJsonParseFailureException(FormCoinsHelper.java:644)
                    at org.lastaflute.web.ruts.process.formcoins.FormCoinsHelper.throwJsonBodyParseFailureException(FormCoinsHelper.java:200)
                    at org.lastaflute.web.ruts.process.ActionFormMapper.throwJsonBodyParseFailureException(ActionFormMapper.java:306)
                    at org.lastaflute.web.ruts.process.ActionFormMapper.mappingJsonBody(ActionFormMapper.java:301)
                    at org.lastaflute.web.ruts.process.ActionFormMapper.handleJsonBody(ActionFormMapper.java:249)
                    at org.lastaflute.web.ruts.process.ActionFormMapper.populateParameter(ActionFormMapper.java:149)
                    at org.lastaflute.web.ruts.ActionRequestProcessor.populateParameter(ActionRequestProcessor.java:221)
                    at org.lastaflute.web.ruts.ActionRequestProcessor.fire(ActionRequestProcessor.java:179)
                    at org.lastaflute.web.ruts.ActionRequestProcessor.process(ActionRequestProcessor.java:114)
                    at org.lastaflute.web.servlet.filter.RequestRoutingFilter.processAction(RequestRoutingFilter.java:289)
                    at org.lastaflute.web.servlet.filter.RequestRoutingFilter.routingToAction(RequestRoutingFilter.java:227)

                    Caused by: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 2 path $
                    at com.google.gson.internal.bind.LaReflectiveTypeAdapterFactory$ReflextiveAdapter.read(LaReflectiveTypeAdapterFactory.java:282)
                    at com.google.gson.Gson.fromJson(Gson.java:991)
                    at com.google.gson.Gson.fromJson(Gson.java:956)
                    at com.google.gson.Gson.fromJson(Gson.java:905)

                    Caused by: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 2 path $
                    at com.google.gson.stream.JsonReader.beginObject(JsonReader.java:385)
                    at com.google.gson.internal.bind.LaReflectiveTypeAdapterFactory$ReflextiveAdapter.read(LaReflectiveTypeAdapterFactory.java:271)
                    at com.google.gson.Gson.fromJson(Gson.java:991)
                    at com.google.gson.Gson.fromJson(Gson.java:956)

                    //////////
                    2022-10-24 09:04:14,178 [http-nio-80-exec-7] DEBUG
                    responseClass=org.apache.catalina.connector.ResponseFacade ; committed=true
                    ; httpStatus=400 ; contentType=null ; locale=ja_JP
                    [header] Set-Cookie=JSESSIONID=175195D9EB5337BDDAD4CE9CFD444D13; Path=/; HttpOnly
                    [request] VirtualHostValue=
                    [request] api_admin_searchlist_apiAdminSearchlistAction_query_Form=VirtualForm:{formMeta:{api_admin_searchlist_apiAdminSearchlistAction_query_Form, org.codelibs.fess.app.web.api.admin.searchlist.SearchBody, props=24}, realForm=null}@1c75fb26
                    [request] lastaflute.action.ACTION_RUMTIME=runtime:{/api/admin/searchlist/query, public JsonResponse ApiAdminSearchlistAction@delete$query(SearchBody), pathParam:{{}}}
                    [request] lastaflute.action.USER_LOCALE=ja_JP
                    [request] lastaflute.config.ACTION_EXECUTE=execute:{public JsonResponse ApiAdminSearchlistAction@delete$query(SearchBody), urlPattern:{query, ^query$}}@4adcd625
                    [session] lastaflute.action.USER_LOCALE=ja_JP
                    • {END}: /api/admin/searchlist/query [00m00s060ms]
                      *400 Bad Request, read the message for the detail

2022-10-24 09:04:14,187 [http-nio-80-exec-8] DEBUG * * * * * * * * * * {BEGIN}: /error/badrequest/
requestClass=org.apache.catalina.connector.RequestFacade ; sessionId=null
; url=http://ホスト/error/badrequest/
; method=DELETE ; protocol=HTTP/1.1 ; scheme=http ; secure=false ; remoteAddr=0:0:0:0:0:0:0:1 ; remoteHost=0:0:0:0:0:0:0:1
; characterEncoding=UTF-8 ; contentLength=-1 ; contentType=null ; locale=ja_JP ; locales=ja_JP
[header] accept=/
[header] authorization=アクセストークン
[header] host=ホスト
[header] user-agent=curl/7.85.0
2022-10-24 09:04:14,190 [http-nio-80-exec-8] DEBUG
/= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = *No routing action:
e.g. expected actions for /error/badrequest/
web.error.ErrorBadrequestAction@index()
web.error.ErrorAction@badrequest()
web.error.badrequest.ErrorBadrequestAction@index()
(and so on…)
= = = = = = = = = =/
2022-10-24 09:04:14,192 [http-nio-80-exec-8] DEBUG
responseClass=org.apache.catalina.connector.ResponseFacade ; committed=true
; httpStatus=405 ; contentType=null ; locale=ja_JP
[header] Allow=OPTIONS, GET, HEAD, POST
[request] VirtualHostValue=

                    • {END}: /error/badrequest/ [00m00s005ms]

ログには、同様に “RequestJsonParseFailureException” が出ています。

“キーワード” とマスクして投稿している部分に、エスケープ処理が必要な文字が含まれていませんか?
ログの RequestJsonParseFailureException を検索して、出なくなるまではデバッグしましょう!

ありがとうございます。

コマンドが通るようになりました。

-d でパラメータを渡す際、全体をシングルクォート で囲っていたのですが
これを ダブルクォート で囲って呼ぶようにしたら正しくコマンドが通るようになりました。

curl がよくわかっておらず、fessとは直接関係ない質問をしてしまい申し訳ありませんでした。

ご教示ありがとうございました。

1 Like

無事に解決できてよかったです。外側のシングルクォートでしたか、気づきませんでした…

curl で fess の管理APIのDELETEを実行する実例は見たことがなかったので、参考になりました!

zolgear 様
shinsuke様とは別の方に回答していただいていたことに今気づきました。

ご回答のおかげで視点を変えて見直すことができました。
(思い込みで見当違いな部分を見てしまっていたので、非常に助かりました。)

こちらでは無事インデックス削除されたことが確認できております。

ありがとうございました。

1 Like