Laravelでcorsってどうやんの?って聞かれたので「そもそもCORSってなんや?」って言えないので調べる。
CORSの基礎知識
よし、わかった。じゃあ後は実践的に試してみる。
Laravelで試すための下準備
3年ぶりにLaravel触るのですっかり忘れてた。やり直し。
環境
t-ito@DESKTOP-BR8SCJA:~/lesson/laravel$ cat /etc/debian_version 12.5 t-ito@DESKTOP-BR8SCJA:~/lesson/laravel$ cat /etc/issue Debian GNU/Linux 12 \n \l t-ito@DESKTOP-BR8SCJA:~/lesson/laravel$ uname -a Linux DESKTOP-BR8SCJA 5.15.146.1-microsoft-standard-WSL2 #1 SMP Thu Jan 11 04:09:03 UTC 2024 x86_64 GNU/Linux
composer使えるようにして、Laravelインストールしてプロジェクト作成
export EDITOR=emacs export LANGUAGE= export LC_ALL=ja_JP.UTF-8 export LANG=ja_JP.UTF-8 PATH=$PATH:$HOME/bin
インストールしてcomposerでcreate-project
localeを設定
apt-get install locales -y sed -i -E 's/# (ja_JP.UTF-8)/\1/' /etc/locale.gen locale-gen
apt install emacs php wget unzip php-json php-xml php-dom php-curl php-sqlite3 php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" php composer-setup.php mv composer.phar ~/bin/composer composer create-project --prefer-dist laravel/laravel SampleProject
で、
$ cd SampleProject $./artisan serve
http://127.0.0.1:8000/ にアクセスする。
オリジンを変えたいのでポートを変えてもう一個Laravelサーバーを作る。
Laravel Porjectを作成
$ cd SampleProject2 $./artisan serve --port 8001
でポートを8081にしてserve
$ ./artisan serve --port=8081
composerコマンドを打つと
Composer could not detect the root package (laravel/laravel) version,
とか言われるので、composer.jsonに
{ "name": "laravel/laravel", "version" : "1.0.0", }
とかversionを適当につけておく。
下準備終わり。
CORSのクライアント側
routes/web.php
<?php Route::get('/client', function () { return view('client'); });
resources/views/client.blade.php
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <title>Laravel</title> </head> <body> CORSのテスト <script> $(()=>{ $.ajax({ url: 'http://127.0.0.1:8081/api/serve' }); }); </script> </body> </html>
CORSのサーバー側
$ ./artisan install:api でAPIのルート作る。
Route::get('/serve', function (Request $request) { return [ 'foo' => 'bar' ]; });
でJSON返すだけのルーティングを追加。
Requestヘッダ
GET /api/serve HTTP/1.1 Accept: */* Accept-Encoding: gzip, deflate, br, zstd Accept-Language: ja,en-US;q=0.9,en;q=0.8 Cache-Control: no-cache Connection: keep-alive Host: 127.0.0.1:8081 Origin: http://127.0.0.1:8080 Pragma: no-cache Referer: http://127.0.0.1:8080/ Sec-Fetch-Dest: empty Sec-Fetch-Mode: cors Sec-Fetch-Site: same-site User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 sec-ch-ua: "Chromium";v="124", "Google Chrome";v="124", "Not-A.Brand";v="99" sec-ch-ua-mobile: ?0 sec-ch-ua-platform: "Windows"
Responseヘッダ
HTTP/1.1 200 OK Host: 127.0.0.1:8081 Date: Fri, 19 Apr 2024 04:19:21 GMT Connection: close X-Powered-By: PHP/8.2.7 Cache-Control: no-cache, private Date: Fri, 19 Apr 2024 04:19:21 GMT Content-Type: application/json Access-Control-Allow-Origin: *
レスポンス側に
Access-Control-Allow-Origin: *
が含まれているので、ブラウザはオリジンが違っていてもアクセス情報を渡してくれる。
プリフライトリクエストを試す。
ちなみに、これだと単純リクエストになるので
<script> $(()=>{ $.ajax({ url: 'http://127.0.0.1:8081/api/serve', headers: { 'X-HTTP-Method-Override': 'PUT', 'Content-Type': 'application/json' } }); }); </script>
とすると、プリフライトリクエストが飛ぶ。
Developerコンソールで見ると、プリフライトの方が後に作られているのに先にサーバーに送られているのがわかる。
CORSを設定する
config/cors.php を作って編集する。 何も指定しないデフォルト状態だと
Access-Control-Allow-Origin: *
がHTTPヘッダについているので、どのサイトからでもAjaxでデータが取り放題になっている。
config/cors.php
<?php return [ 'allowed_origins' => [ ], ];
とりあえず、これをするだけでHTTPヘッダから「Access-Control-Allow-Origin」自体が消えてクロスサイトでAjaxは取れなくなる。
改めて許可リストに入れたい場合は config/cors.php
<?php return [ 'allowed_origins' => [ 'http://127.0.0.1:8080', ], ];
としておくと、プリフライトに
Access-Control-Allow-Origin:http://127.0.0.1:8080
が入るのでデータの取得ができる。 別のオリジンからも許可したい場合は配列に加えるとよい。その場合合致した1つのオリジンのみがAccess-Control-Allow-Originヘッダに記載される。ちなみに、ポートだけはワイルドカードが効くみたい。 config/cors.php
<?php return [ 'allowed_origins' => [ 'http://127.0.0.1:*', ], ];
あとのオプションとかは、