axios通信で、画像ファイルとそれ以外の文字や数値を同時に送信する方法について、2日ほどはまってしまったので備忘録として残しておきます。
なお、後半部分のAWSへの画像データ保存については詳しく扱いませんのでご了承ください。
■開発環境
OS:windows10
Laravel 8.83.14
Vue.js 2.6.12
■実現したかったこと
画像ファイルとjson形式の文字データを同時にaxiosでlaravelコントローラーに送信したい。
■正しい送信の仕方
①コンポーネントで画像ファイルを取得
まず、コンポーネントで選択された画像ファイルをdataにいれる
indexComponent.vue
data: function(){
return{
newUser:{
selectImg:"",
selectName:Taro,
selectAge:19,
}
}
},
methods:{
async register(e){
//ファイルデータを代入
this.selectImg = e.target.files[0]
await this.$store.dispatch('todo/register', this.newUser)
}
}
②vuexでFormDataに値を代入する
vuex.js
async register(context, data){
//入力用のFormDataを定義
const formData = new FormData()
//dataでコンポーネントから受け取った値をそれぞれいれていく
formData.append('file',data.)
formData.append('img',data.selectImg)
formData.append('name',data.selectName)
formData.append('age',data.selectAge)
//config定義(headersを指定)
const config = {headers:{
'Content-Type' : 'multipart/form-data'
}}
await axios.post('/api/registerUser', formData, config )
//ここで、以下のようにするとコントローラー側でデータがnullになってしまい、処理が止まる
//const newUser = {
// name:data.selectName,
// age:data.selectAge,
// }
//const formData = new FormData()
//
//formData.append('newUser', newUser)
//formData.append('img',data.selectImg)
}
③コントローラー側で受け取る
registerController.php
use Illuminate\Support\Str;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
public function registerUser(Request $request)
{
//バリデーション
$request->validate([
'name' =>[ 'required', 'string', 'max:255'],
'age' => ['int'],
'img' => ['image', 'mimes:jpg,jpeg,png,gif','max:10240','nullable'],
]);
//formDataの値は、
//1.文字列は、$request->nameのように、append()で指定した第一引数からデータを取得できる
$registName = $request->name;
//2.ファイルは、$request->file('img')のように指定すると取得できる
$registImg = $request->file('img');
//3.formDataはint型でデータを送信できないため、int型でデータを取得したい場合は、
// *1を末尾に付け加えて、数式にする
$registAge = $request->age *1;
//以降はデータベースの処理を行う
//例えば、AWS S3に画像データを保存し、データベースにファイル名を保存するなら
//ファイル名用のランダムな文字列を生成
$randomName = Str::random(12);
//ファイル名末尾につける拡張子を取得
$extension = $request->file->extension();
//ファイル名を生成
$FileName = $randomName.'.'.$extension;
//AWS S3クラウドに画像データを保存
Storage::cloud()->putFileAs('',$registImg, $FileName,'public');
//ORMを使用するため、ユーザーモデルをインスタンス化
$user = new User;
//トランザクション処理開始
//トランザクション処理は、try~catchの直前に書くこと)
DB::beginTransaction();
try{
$user->name = $registName;
$user->age = $registAge;
$user->img = $fileName;
$user->save();
//DB::commit();を行わないと、save()が実行されるにも関わらず、データベースに
//データが保存されないようになるので注意!!
DB::commit();
} catch (\Exception $exception){
//データベースへの保存が失敗した場合
//データベースをロールバック+AWSに保存した画像データを消去
DB::rollback();
Storage::cloud()->delete($FileName);
throw $exception;
}
User.php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
use HasFactory;
protected $table = "users";
protected $fillable = ['name', 'age', 'img'];
}