LoginSignup
1
0

More than 3 years have passed since last update.

nuxtのformからPOSTされたデータをgoのサーバで受け取る(私的メモ)

Last updated at Posted at 2020-08-11

nuxt.js(vueファイル)

Vuetifyのコンポーネントを活用し、formを作成、validationとresetボタンを実装しました。

<template>
  <v-form ref="form" v-model="valid">
    <v-text-field
      v-model="title"
      :counter="10"
      :rules="titleRules"
      label="Title"
      required
    ></v-text-field>

    <v-textarea
      v-model="description"
      :counter="100"
      :rules="descriptionRules"
      label="Description"
      required
    ></v-textarea>

    <v-textarea
      v-model="content"
      :counter="100"
      :rules="contentRules"
      label="Content"
      required
    ></v-textarea>

    <v-btn :disabled="!valid" color="success" class="mr-4" @click="submit">
      SUBMIT
    </v-btn>

    <v-btn color="error" class="mr-4" @click="reset">
      Reset Form
    </v-btn>
  </v-form>
</template>

<script>
export default {
  data: () => ({
    valid: false,
    title: '',
    titleRules: [
      (v) => !!v || 'Title is required',
      (v) => (v && v.length <= 20) || 'Title must be less than 20 characters',
    ],
    description: '',
    descriptionRules: [
      (v) => !!v || 'Description is required',
      (v) =>
        (v && v.length <= 100) ||
        'Description must be less than 100 characters',
    ],
    content: '',
    contentRules: [
      (v) => !!v || 'Content is required',
      (v) =>
        (v && v.length <= 100) || 'Content must be less than 100 characters',
    ],
  }),
  methods: {
    post() {
      this.$axios.$post('http://localhost:10000/articles', {
        title: this.title,
        desc: this.description,
        content: this.content,
      })
    },
    submit() {
      this.$refs.form.validate()
      if (this.valid) {
        this.post()
        alert('' + this.title + '」を登録しました。')
        document.location = '/articles'
      }
    },
    reset() {
      this.$refs.form.reset()
    },
  },
}
</script>

validationに合格するとsubmitボタンの色が変化し、ボタンをクリックするとイベントが発火しsubmit()が呼ばれます
その中で、post()メソッドを呼び出し$axiosモジュールを使ってAPIサーバにPOSTメソッドをデータ付きで送信します。axiosはデフォルトでContent-Typeをapplication/jsonで通信します。

go

# CORS対策
func withCORS(fn http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Content-Type", "application/json")
        w.Header().Set("Access-Control-Allow-Origin", "*")
        fn(w, r)
    }
} 

# muxにハンドラを登録している部分です(gorilla/muxを使用)
myRouter.HandleFunc("/articles", withVars(withDB(db, withCORS(createNewArticle)))).Methods("POST")



# 登録してるハンドラ定義部分です
func createNewArticle(w http.ResponseWriter, r *http.Request) {
    log.Println("called createNewArticle")

    # db接続
    d := GetVar(r, "db").(Database)
    db := d.init()

    # JsonをArticle構造体としてパース
    article := ParseJsonArticle(w, r)

    # 検証と保存
    if valid := article.validate(); valid {
        db.Create(&article)
        if db.NewRecord(article) {
            log.Println("新規articleの保存に失敗しました。")
        }
    }
}

フォームから適当なデータを送ってみると....

(一部)
Access to XMLHttpRequest at 'http://localhost:10000/articles' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
xhr.js:178 POST http://localhost:10000/articles net::ERR_FAILED

CORSポリシーでクライアントからサーバーへのリクエストがブロックされていると怒られています。
特にこの部分、
Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

'Access-Control-Allow-Origin' ヘッダーはgoでハンドラの直前にチェインさせている関数(withCORS)で確かに付与しているハズ...

(。´・ω・)ん?

go側のログを見る限り、ハンドラ関数に到達すらしていない模様。

こんな記事がありました。
https://qiita.com/att55/items/2154a8aad8bf1409db2b

プリフライトリクエストとシンプルリクエストなんてものがあるようです。

Content-Type=''application/json"の場合、クロスオリジン(ドメインかポートがサーバとクライアントで違う)の場合、一旦OPTIONSメソッドが走り、安全確認できたら本メソッドが走るイメージかなと理解します。
https://github.com/gorilla/mux#user-content-handling-cors-requests
に沿って、サーバ側のコードを直します。

func articlesCORSHandling(w http.ResponseWriter, r *http.Request){
    # レスポンスヘッダーの追加
    w.Header().Set("Access-Control-Allow-Origin","http://localhost:3000")
    w.Header().Set( "Access-Control-Allow-Headers", "Origin, ContentType,")
    w.Header().Set( "Access-Control-Allow-Methods","GET, POST, OPTIONS" )

    # GETメソッド
    if r.Method == http.MethodGet {
        log.Println("called GET /articles")
        d := GetVar(r, "db").(Database)
        db := d.init()
        var articles Articles
        db.Find(&articles)
        json.NewEncoder(w).Encode(articles)
    }

    # POST メソッド
    if r.Method == http.MethodPost {
        log.Println("called POST /articles")
        d := GetVar(r, "db").(Database)
        db := d.init()
        article := ParseJsonArticle(w, r)
        log.Println(article)
        if valid := article.validate(); valid {
            // log.Println("valid!!")
            db.Create(&article)
            if db.NewRecord(article) == false {
                log.Println("新規articleを保存しました")
            }else {
                log.Println("新規articleの保存に失敗しました。")
            }
        }
    }

}

func handleRequests() {
    r := mux.NewRouter()
    r.HandleFunc("/articles", withVars(withDB(db, articlesCORSHandling))).Methods(http.MethodGet, http.MethodPost, http.MethodOptions)
    r.Use(mux.CORSMethodMiddleware(r))
    log.Fatal(http.ListenAndServe(":10000", r))
}

withCORSを関数内部に統合させる形でハンドラを定義し登録してます。
再度、適当なデータを送信してみると...

2020/08/11 12:44:48 called POST /articles
2020/08/11 12:44:48 {{0 0001-01-01 00:00:00 +0000 UTC 0001-01-01 00:00:00 +0000 UTC <nil>} test test test}
2020/08/11 12:44:48 新規articleを保存しました

成功しました。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0