【メモ】Laravel9.xのHTTPファサードでPOSTしてもデータが取得出来なかった件への対処

LaravelのHTTPファサード(Guzzleのラッパー)を使ってローカルのAPIにデータをPOSTする処理を書いていたのですが、なぜかAPI側でデータ取得出来なくてはまりました。その解消のためのメモ






動作環境概要

  • [ホストOS] Windows 11
  • [ゲストOS] Debian 11(Docker)

URI

  • [フォーム] https://site-A.hoge.com(Laravel 9.13.0)
  • [API] https://site-B.hoge.com/api/regist(独自フレームワーク)

処理手順

  1. フォームにアクセスすると入力フォームを表示する
  2. submitするとフォーム自身にPOST送信
  3. フォームの処理メソッドの中で、HTTP::post()を実行してAPIにPOST
  4. 結果を受け取ってリダイレクト


素直にフォーム → APIとリクエストを投げるのではなく、1回フォーム側でデータを受け取り整形してからAPIに投げるという形です。本来そんな面倒なことする必要はないのですが、API側のフレームワークがオレオレフレームワークで非常に使いづらいので、出来ることはなるべくやっておくほうが後々幸せになれるため、そんな面倒なことをやってます。

また本番環境になるべく近づけたいのと、安全性に関する警告が出るのが鬱陶しいのとで、どちらもオレオレSSLでhttps化しています。


基本的な処理コード(抜粋)

use Http;

$response = Http::post('https://site-B.hoge.com/api/regist', [
   'key' => 'value',
]);






問題その1:SSL certificate problem: unable to get local issuer certificate

普通にPOSTすると以下のエラーが出ます。


cURL error 60: SSL certificate problem: unable to get local issuer certificate (see https://curl.haxx.se/libcurl/c/libcurl-errors.html) for https://site-B.hoge.com/api/regist


提示されたURLを読むと、


CURLE_PEER_FAILED_VERIFICATION (60)
The remote server’s SSL certificate or SSH md5 fingerprint was deemed not OK. This error code has been unified with CURLE_SSL_CACERT since 7.62.0. Its previous value was 51.

libcurl – Error Codes


とあり、ネットで検索すると「証明書を持ってきて配置すれば直るよ」的なことが書いてありますが、上手いこと証明書を設定出来ませんでした(Guzzleオプションのcertを使えばできるのかも)。本番環境でどうするかは別途考えることとして、ここでは証明書チェックを回避するオプションを付加して逃げておきます。

改修後の処理コード(抜粋)

use Http;

$response = Http::withOptions([
   'verify' => false,
])->post('https://site-B.hoge.com/api/regist', [
   'key' => 'value',
]);



問題その2:$_POSTが空になってしまう

APIにPOSTは出来ていて200が返ってきていますが、API側でデータを確認すると空になってしまいます。いやあ、これはよくわからなくてすごい嵌まりました。結論から言うと次のように改修するとデータが取得出来るようになります。


改修後の処理コード(抜粋)

use Http;

$response = Http::asForm()->withOptions([
   'verify' => config('app.debug') ? false : true,
])->post('https://site-B.hoge.com/api/regist', [
   'key' => 'value',
]);


フォームURLエンコードされたリクエストの送信
application/x-www-form-urlencodedコンテンツタイプを使用してデータを送信する場合は、リクエストを行う前にasFormメソッドを呼び出す必要があります。

HTTPクライアント 9.x Laravel

ただし、パラメータの送信は初期状態ではapplication/jsonとして送信されることになります。そのため、実際のフォーム送信のようにする場合はasForm()と一緒に使ってください。

Laravel 7.xの新しいHTTP Client!実例 – console dot log


ああ……そういうこと。application/jsonとして送信されたデータは$_POSTでは受け取れないので、API側で一工夫する必要があったんですね。

ということはasForm()を使わなくても例えば以下のような処理をすればデータを取り出すことが出来ます。こっちの方がシンプルかも。


$json = file_get_contents('php://input')
$data = json_decode($json, true);



おまけ:Cookieも送りたい

POST通信はデフォルトではCookieを送信しませんが、セッション情報を共有するためにCookieを送信したい。というわけで、withCookiesを使いましょう。ドメインが共通とか諸々Cookie側の制限はありますが、それをクリアしているならこれでCookieのやり取りも出来ます。



最終的なPOST処理コード

use Http;

$response = Http::withOptions([
   'verify' => false,
])->withCookies([
   'token' => 'sample'
], 'hoge.com')
->post('https://site-B.hoge.com/api/regist', [
   'key' => 'value',
]);


無事、データが渡せました。めでたしめでたし。