皆さんこんにちは!
Windowsで開発している僕にとってはSafari特有のエラー程苦しむものは無いです。
ただ、この時代スマートフォンの使用率が圧倒的に高い10代、20代のほとんどはiPhoneを使っていると思います。
僕の周りでもiPhoneの使用率が圧倒的に高いです。
なので、iPhoneのエラーも無視するわけにはいかない。。。
今日はそんなこんなでaxiosでLaravelで作成したバックエンドとの通信でWindows環境で開発しているので、エラー内容は確認できなかったのですが、おそらくCORSエラーが原因でAPI通信を行うことができませんでした。
結論から言いますと、SafariではChromeのように上手くキャッシュの処理を行うことができないそうです。
なので、このキャッシュの問題を解決してあげることでSafariでもAPI通信を行うことができます!
それでは、説明を見ていきましょう!
#はじめに#
今回は、Vueでの説明となります。
もし、Reactなどを使っている場合は適時変更して下さい。
また、バックエンドではLaravelでCORSドメインの設定などを行います。
もし、Laravel以外でAPIを作成している場合も適時変更してください。
#axiosでCookie設定#
axiosのデフォルトでは、withCredentials
というCookieを使えるようにするためのプロパティの設定がOFFになっています。
なので、これをONにしてあげましょう!
// axiosのプロトタイプ宣言
Vue.prototype.$axios = axios
// Cookieの使用を可とする
axios.defaults.withCredentials = true
これでaxiosがデフォルトでCookieを使用することができます。
#CORSドメイン設定#
次に、axiosでCookieの情報を受け取るためにバックエンドで適切なヘッダーを追加してあげましょう!
> php artisan make::middleware ApiCors
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class ApiCors
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle(Request $request, Closure $next)
{
// すべてのレスポンスに CORS 用のヘッダーを追加する必要はないので URL から判断する
$paths = explode('/', $request->getPathInfo());
if ($paths[1] === 'api') {
return $next($request)
->header('Access-Control-Allow-Origin', config('cors.allowed_origins'))
->header('Cache-Control', 'no-cache max-age=3600')
->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')
->header('Access-Control-Allow-Credentials', 'true')
->header('Access-Control-Allow-Headers', 'X-XSRF-TOKEN, Authorization, content-type, Transfer-Encoding, Accept, Accept-Encoding, Accept-Language');
}
return $next($request);
}
}
$paths = explode('/', $request->getPathInfo());
とif ($paths[1] === 'api')
で`/api/apis```のようなAPI通信を行う時だけこのミドルウェアを適用するようにしています。
##Access-Control-Allow-Origin##
Access-Control-Allow-Origin
ではCORSドメインを許可するドメインを登録しています。
例えば、http://localhost:3000
からのリクエストを許可したい場合はここにhttp://localhost:3000
と入力してください。
これを*
のようにすると全てのドメインからリクエストが可能なので、データ抜き放題となるので注意して下さい。
##Access-Control-Allow-Methods##
Access-Control-Allow-Methods
では、使用できるメソッドを書きます。ほとんどの場合は上記のようにしてOKです。
##Access-Control-Allow-Credentials##
Access-Control-Allow-Credentials
をtrue
にすることで、先ほどaxiosで設定したCookie情報のリクエストを受け取れるようにしています。
##Access-Control-Allow-Headers##
最後に、Access-Control-Allow-Headers
を説明します。
これが重要です!
色々あるのですが2つだけ説明します。
X-XSRF-TOKEN
はaxiosで発行したトークン情報です。PHPで言うと、form
のCSRF
のようなものです。これを受け取るためにこのヘッダーを追加します。
次に、content-type
です。
これは、GETやHEADの場合は必要ないのですが、以下のようなリクエストを行う場合content-type
はapplicatio/json
となります。
this.$axios
.post(process.env.VUE_APP_LARAVEL_SITE_URL + '/api/participants', {
name: 'akki'
})
そして、content-type
のデフォルトではapplication/json
は対応していません。
なので、このようなapplication/json
の形を受け取るのを許可するためにcontent-type
を追加します。
ちなみに場合によっては、content-type
でエラーが出ます。その時はContent-Type
と設定して見て下さい。
##ミドルウェアの適用##
最後に作成したこのミドルウェアを適用させましょう!
App/Http/Middleware/Karnel.php
を開いてください。
<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
/**
* The application's global HTTP middleware stack.
*
* These middleware are run during every request to your application.
*
* @var array
*/
protected $middleware = [
// \App\Http\Middleware\TrustHosts::class,
// CORSドメインの設定を追加
\App\Http\Middleware\ApiCors::class,
\App\Http\Middleware\TrustProxies::class,
\Fruitcake\Cors\HandleCors::class,
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
];
// 省略
}
必ず**$middleware**に追加してください!!
なぜかと言うと、$middlewareに追加しないとOPTIONS
リクエストに今作成したミドルウェアを適用することができません!
絶対に**$middleware**に追加!!!
いかがだったでしょうか?
このエラーで3日程時間を費やされたので、本当に苦労しました。
ぜひ皆さんのお力になれたらなと思います。
以上、「axiosでREST APIの通信を行う時にSafariではエラーが起きたときの対処法」でした!
また、何か間違っていることがあればご指摘頂けると幸いです。
他にも初心者さん向けに記事を投稿しているので、時間があれば他の記事も見て下さい!!
あと、最近「ココナラ」で環境構築のお手伝いをするサービスを始めました。
気になる方はぜひ一度ご相談ください!
Thank you for reading