🦨

nginx + goでファイルアップロード時にcorsエラー

1 min read

対象読者

nginx

  • ファイルアップロードの時だけcorsエラーが出る。
  • ファイルのサイズによってアップロードできたり、できなかったりするエラーに遭遇した方。

バックグラウンド

Nextjsからバックエンドのgoを通してS3に画像をアップロード。アップロードに成功したらそのurlをDBに保存するという処理でcorsエラーにあいました。
ローカルだと動くのでおそらくnginxだろうな~となんとなく思いつつもなかなか原因が見つからず解決できない。
しかも、なぜかcorsエラーが出る画像と出ない画像があるぞ!?
運営者ギルドのアドバイスをもらえるチャンネルで相談をしてみるも、そういった事象に遭遇したことのある方はいませんでした。

因みにAPIサーバーの仕組みはこちらの記事で紹介しているので興味ある方は見てみて下さい。

https://zenn.dev/maru44/articles/84004e084112fa

もがく

https://stackoverflow.com/questions/25568629/cors-error-upload-file-4mb

こちらの記事にあるようにアップロードサイズがnginxのclient_max_body_sizeを上回るとcorsエラーを返すらしい。
ということでgoとnginxでリクエストボディのサイズを良しなに指定してみることにしてみた。

まずはgo側でリクエストボディのサイズ制限を明示してみる。

sample_view.go
func Smaple(w http.ResponseWriter, r *http.Request) error {
    r.Body = http.MaxBytesReader(w, r.Body, 40*1024*1024) // 40MB
    
    // 以下略
}

そしてnginx側も以下のコードをhttp, server, locationすべてに挿入(やけくそじゃないか)

client_max_body_size 40M;

しかし直らない。他にもごちゃごちゃやったが、何も効果がない。
こういう時は何をやってもダメだ。私は寝た zzz。

解決

PUTメソッドで原因を特定してたのですが、PUTだとnginxのログがなぜか出ずにかなりの時間を費やしてしまいました。恐らくpreflightがある所為。

そこで翌朝POSTメソッドで検証。
そしたら以下のエラーログが!!!

2021/06/14 10:39:01 [crit] 13438#0: *19 open() "/var/lib/nginx/tmp/client_body/0000000003" failed (13: Permission denied), client: ***.**.***.***, server: <backend>, request: "POST /admin/anime/post/ HTTP/1.1", host: "<backend>", referrer: "<frontend>"

この世にエラーログが出ることほど嬉しいことは無い

ちゃっちゃとなおしてしまおう。

sudo chown -R nginx:nginx /var/lib/nginx

この1行で解決!!

原因

原因は恐らく以下が考えられます。
大きいファイルがアップロードされたときnginxで一時的にキャッシュしているようです。キャッシュ先へのアクセス権限がなかったことが原因でした。

まとめ

Djnangoではこのようなエラーに遭遇したことはなかったので、Django等のフレームワークにはファイルアップロードに対して一時的にキャッシュしてくれる機構を用意してくれているんだと思います。

今回バックエンドはgoを使用。ORMやフレームワークを使用せず、3rdパーティー系のライブラリもほとんど使わず開発していました(S3とfirebase authはご愛嬌)。
こういうエラーに遭遇するとフレームワーク等がいかによくできてるか再認識させられますね。