Herokuで公開した自作アプリでのPOSTした際にserver errror 500が返る原因と対策をご教授ください。
###問題点
Vueファイル内のformData APIをPOSTするとserver error 500が返ってきます。
Laravelを使用しています。
※lockalhost:8000ではエラーにならずに正常にPOSTできAWS S3に保存されます。
GETで取得・表示することもできています。
※問題はHerokuで公開したURLで同じようにPOSTをする時だけserver error 500となってしまうことです。
###コンソールエラー
error
1app.js:14719 POST https://portfolio-vue-laravel.herokuapp.com/api/photos 500 (Internal Server Error) 2dispatchXhrRequest @ app.js:14719 3xhrAdapter @ app.js:14553 4dispatchRequest @ app.js:15199 5Promise.then (async) 6request @ app.js:14976 7Axios.<computed> @ app.js:15001 8wrap @ app.js:15565 9_callee$ @ app.js:17629 10tryCatch @ app.js:19187 11invoke @ app.js:19417 12(anonymous) @ app.js:19242 13asyncGeneratorStep @ app.js:17535 14_next @ app.js:17537 15(anonymous) @ app.js:17537 16(anonymous) @ app.js:17537 17submit @ app.js:17665 18submit @ app.js:22527 19invokeWithErrorHandling @ app.js:28295 20invoker @ app.js:28620 21original._wrapper @ app.js:33979
error
1[Vue warn]: Error in v-on handler (Promise/async): "Error: Request failed with status code 500" 2 3found in 4 5---> <PhotoForm> at resources/js/pages/PhotoForm.vue 6 <App> at resources/js/App.vue 7 <Root> 8warn @ app.js:27066 9logError @ app.js:28325 10globalHandleError @ app.js:28320 11handleError @ app.js:28280 12(anonymous) @ app.js:28297 13Promise.catch (async) 14invokeWithErrorHandling @ app.js:28297 15invoker @ app.js:28620 16original._wrapper @ app.js:33979
error
1app.js:28329 Error: Request failed with status code 500 2 at createError (app.js:15133) 3 at settle (app.js:15394) 4 at XMLHttpRequest.handleLoad (app.js:14602) 5logError @ app.js:28329 6globalHandleError @ app.js:28320 7handleError @ app.js:28280 8(anonymous) @ app.js:28297 9Promise.catch (async) 10invokeWithErrorHandling @ app.js:28297 11invoker @ app.js:28620 12original._wrapper @ app.js:33979
###該当コード
Vue
1<template> 2 <div class="postPhoto"> 3 <h3>投稿する写真を選んでください</h3> 4 <form class="postPhoto_form" @submit.prevent="submit"> 5 6 <input type="file" class="postPhoto_form-item" 7 @change="onFileChange" 8 name="file"> 9 10 <output class="postPhoto_form-output" v-if="preview"> 11 <img :src="preview" alt=""> 12 </output> 13 14 <div class="postPhoto_form-button"> 15 <button type="submit" class="button">送信</button> 16 </div> 17 </form> 18 </div> 19</template>
Vue
1<script> 2export default { 3 data() { 4 return { 5 preview: null, 6 photo: null, 7 } 8 }, 9 methods: { 10 onFileChange(event) { 11 const reader = new FileReader() 12 reader.onload = e => { 13 this.preview = e.target.result 14 } 15 reader.readAsDataURL(event.target.files[0]) 16 this.photo = event.target.files[0] 17 }, 18 19 reset() {略}, 20 21 async submit() { 22 const formData = new FormData() 23 if (this.photo !== "") { 24 formData.append('photo', this.photo) 25 } 26 const config = { headers: { "content-type": "multipart/form-data" } }; 27 const response = await axios.post('/api/photos', formData, config) 28 29 if (response.status === UNPROCESSABLE_ENTITY) { 30 this.errors = response.data.errors 31 console.log(this.errors); 32 return false 33 } 34 35 this.reset() 36 37 if (response.status !== CREATED) { 38 this.$store.commit('error/setCode', response.status) 39 return false 40 } 41 42 this.$router.push(`/photoList`) 43 }, 44 } 45} 46</script>
PhotoControllerphp
1 /** 2 * 写真投稿 3 * @param StorePhoto $request 4 * @return \Illuminate\Http\Response 5 */ 6 public function create(StorePhoto $request) 7 { 8 // 投稿写真の拡張子を取得する 9 $extension = $request->photo->extension(); 10 11 $photo = new Photo(); 12 13 // インスタンス生成時に割り振られたランダムなID値と 14 // 本来の拡張子を組み合わせてファイル名とする 15 $photo->filename = $photo->id . '.' . $extension; 16 17 // S3にファイルを保存する 18 // 第三引数の'public'はファイルを公開状態で保存するため 19 Storage::cloud() 20 ->putFileAs('', $request->photo, $photo->filename, 'public'); 21 22 // データベースエラー時にファイル削除を行うため 23 // トランザクションを利用する 24 DB::beginTransaction(); 25 26 try { 27 Auth::user()->photos()->save($photo); 28 DB::commit(); 29 } catch (\Exception $exception) { 30 DB::rollBack(); 31 // DBとの不整合を避けるためアップロードしたファイルを削除 32 Storage::cloud()->delete($photo->filename); 33 throw $exception; 34 } 35 36 // リソースの新規作成なので 37 // レスポンスコードは201(CREATED)を返却する 38 return response($photo, 201); 39 }
StorePhotophp
1<?php 2 3namespace App\Http\Requests; 4 5use Illuminate\Foundation\Http\FormRequest; 6 7class StorePhoto extends FormRequest 8{ 9 /** 10 * Determine if the user is authorized to make this request. 11 * 12 * @return bool 13 */ 14 public function authorize() 15 { 16 return true; 17 } 18 19 /** 20 * Get the validation rules that apply to the request. 21 * 22 * @return array 23 */ 24 public function rules() 25 { 26 return [ 27 'photo' => 'required|file|mimes:jpg,jpeg,png,gif' 28 ]; 29 } 30}
Photophp
1<?php 2 3namespace App; 4 5use Illuminate\Database\Eloquent\Model; 6use Illuminate\Support\Arr; 7use Illuminate\Support\Facades\Storage; 8 9class Photo extends Model 10{ 11 /** プライマリキーの型 */ 12 protected $keyType = 'string'; 13 14 /** JSONに含める属性 */ 15 protected $visible = [ 16 'id', 'owner', 'url', 'created_at' 17 ]; 18 19 /** JSONに含める属性 */ 20 protected $appends = [ 21 'url', 22 ]; 23 24 /** IDの桁数 */ 25 const ID_LENGTH = 12; 26 27 public function __construct(array $attributes = []) 28 { 29 parent::__construct($attributes); 30 31 if (! Arr::get($this->attributes, 'id')) { 32 $this->setId(); 33 } 34 } 35 36 /** 37 * ランダムなID値をid属性に代入する 38 */ 39 private function setId() 40 { 41 $this->attributes['id'] = $this->getRandomId(); 42 } 43 44 /** 45 * ランダムなID値を生成する 46 * @return string 47 */ 48 private function getRandomId() 49 { 50 $characters = array_merge( 51 range(0, 9), range('a', 'z'), 52 range('A', 'Z'), ['-', '_'] 53 ); 54 55 $length = count($characters); 56 57 $id = ""; 58 59 for ($i = 0; $i < self::ID_LENGTH; $i++) { 60 $id .= $characters[random_int(0, $length - 1)]; 61 } 62 63 return $id; 64 } 65 66 /** 67 * アクセサ - url 68 * @return string 69 */ 70 public function getUrlAttribute() 71 { 72 return Storage::cloud()->url($this->attributes['filename']); 73 } 74 75 /** 76 * リレーションシップ - usersテーブル 77 * @return \Illuminate\Database\Eloquent\Relations\BelongsTo 78 */ 79 public function owner() 80 { 81 return $this->belongsTo('App\User', 'user_id', 'id', 'users'); 82 } 83}
ローカルホストではAWS S3に保存できているのでenvファイルの設定は正しいかと思います。
コンソールエラーからリクエストに問題があるように見えるのですがどこがどう間違っているのかが分かりませんでした。
色々調べた結果formData APIはmacOSやSafariで上手く送信できないととかも拝見したのですが結局よく分かりませんでした。
そもそもローカルホストでは正常に動いているのでHeroku公開でのサイトではAWS S3へ接続がうまくできていないのでしょうか。
どなたかご教授のほどを宜しくお願いします。
###環境
- vue:2.6.12
- PHP:7.4.13
- Laravel:2.3.0
- MySQL:8.0.22 for osx10.13 on x86_64 (Homebrew)
- macOS High Sierra 10.13.6
参考にしたサイト
https://www.hypertextcandy.com/vue-laravel-tutorial-introduction/
こちらの記事を参考に作成しています。
回答1件
あなたの回答
tips
プレビュー