我想在React中向使用Golang创建的API进行POST请求。

huangapple go评论85阅读模式
英文:

I want to POST from React to an API created in Golang

问题

我想做什么

我正在为我的 Golang 学习创建一个 Todo 应用程序。
我想用 React 和 Golang 从 POST 请求中读取数据。

代码

Go 后端

package todos

import (
	"database/sql"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"
	"time"
	"todo-app/auth"

	"github.com/joho/godotenv"
)

type Todo struct {
	// UserID    int       `json:"userid"`
	Todo      string    `json:"todo"`
	CreatedAt time.Time `json:"createdat"`
	UpdatedAt time.Time `json:"updatedat"`
}

type TodoBody struct {
	Todo string `json:"todo"`
}

func CreateTodo(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "*")
	w.Header().Set("Access-Control-Allow-Origin", "http://localhost:3000")
	w.Header().Set("Access-Control-Allow-Credentials", "true")
	w.Header().Set("Access-Control-Allow-Headers", "*")

	e := godotenv.Load()
	if e != nil {
		log.Fatal(e)
	}
	dbConnectionInfo := fmt.Sprintf("%s:%s@tcp(127.0.0.1:3306)/go_todo", os.Getenv("DB_USER"), os.Getenv("DB_PASSWORD"))
	db, err := sql.Open("mysql", dbConnectionInfo)
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	tokenString := r.Header.Get("Authorization")
	tokenString = strings.TrimPrefix(tokenString, "Bearer ")

	log.Printf("request token=%s\n", tokenString)

	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		log.Fatal(err)
	}

	log.Printf("request body=%s\n", body)

	var data TodoBody

	if err := json.Unmarshal(body, &data); err != nil {
		log.Println(err)
	}

	// userId := 12
	todo := data.Todo

	todoData := Todo{todo, time.Now(), time.Now()}

	_, err2 := auth.TokenVerify(tokenString)
	if err2 != nil {
		log.Fatal(err)
	} else {

		stmt, err := db.Prepare("INSERT INTO todos (Todo,CreatedAt,UpdatedAt) VALUES(?,?,?)")
		if err != nil {
			log.Fatal(err)
		}

		_, err = stmt.Exec(todoData.Todo, todoData.CreatedAt, todoData.UpdatedAt)
		if err != nil {
			log.Fatal(err)
		}

		json.NewEncoder(w).Encode(todoData)
	}
}

React 前端

import { useState } from "react";
import { useCreateTodo } from "../../hooks/useCreateTodo";
import { BaseButton } from "../atoms/baseButton";
import { TextArea } from "../atoms/textArea";

export const AddTodo = () => {
  const [text, setText] = useState("");
  const CreateTodo = useCreateTodo();
  const token = "Bearer " + sessionStorage.getItem("token");

  const onClickCreate = () => {
    CreateTodo(token, text);
  };

  return (
    <div>
      <TextArea
        onChange={(e) => setText(e.target.value)}
        defaultValue=""
      />

      <BaseButton text="タスクを追加" onClick={onClickCreate} />
    </div>
  );
};

POST 请求如下

import axios from "axios";

export const useCreateTodo = () => {
  const CreateTodo = (token, todo) => {
    const URL = "http://127.0.0.1:8080/createtodo";

    const data = { todo: todo };
    console.log(data);

    axios
      .post(URL, JSON.stringify(data), { headers: { Authorization: token } })
      .then((res) => console.log(res))
      .catch((err) => console.log(err));
  };

  return CreateTodo;
};

如果我在 POST 请求中不添加头部信息,正确的值会传递到 Go 的 ioutil.ReadAll(r.Body) 中,但是如果我添加头部信息,我无法获取到值。
当我使用 Advanced REST client 发送请求到 Go 的 API 时,即使带有头部信息,它也能正确处理,所以我想知道是否存在 POST 方法的问题,但是我似乎无法解决这个问题。
非常感谢您的帮助。祝好。

英文:

What I want to do

I am creating a Todo app for my Golang studies.
I would like to read the data from POST requests in React with Golang.

Code

go Backend

package todos
import (
&quot;database/sql&quot;
&quot;encoding/json&quot;
&quot;fmt&quot;
&quot;io/ioutil&quot;
&quot;log&quot;
&quot;net/http&quot;
&quot;os&quot;
&quot;strings&quot;
&quot;time&quot;
&quot;todo-app/auth&quot;
&quot;github.com/joho/godotenv&quot;
)
type Todo struct {
// UserID    int       `json:&quot;userid&quot;`
Todo      string    `json:&quot;todo&quot;`
CreatedAt time.Time `json:&quot;createdat&quot;`
UpdatedAt time.Time `json:&quot;updatedat&quot;`
}
type TodoBody struct {
Todo string `json:&quot;todo&quot;`
}
func CreateTodo(w http.ResponseWriter, r *http.Request) {
w.Header().Set(&quot;Content-Type&quot;, &quot;*&quot;)
w.Header().Set(&quot;Access-Control-Allow-Origin&quot;, &quot;http://localhost:3000&quot;)
w.Header().Set(&quot;Access-Control-Allow-Credentials&quot;, &quot;true&quot;)
w.Header().Set(&quot;Access-Control-Allow-Headers&quot;, &quot;*&quot;)
e := godotenv.Load()
if e != nil {
log.Fatal(e)
}
dbConnectionInfo := fmt.Sprintf(&quot;%s:%s@tcp(127.0.0.1:3306)/go_todo&quot;, os.Getenv(&quot;DB_USER&quot;), os.Getenv(&quot;DB_PASSWORD&quot;))
db, err := sql.Open(&quot;mysql&quot;, dbConnectionInfo)
if err != nil {
log.Fatal(err)
}
defer db.Close()
tokenString := r.Header.Get(&quot;Authorization&quot;)
tokenString = strings.TrimPrefix(tokenString, &quot;Bearer &quot;)
log.Printf(&quot;request token=%s\n&quot;, tokenString)
body, err := ioutil.ReadAll(r.Body)
if err != nil {
log.Fatal(err)
}
log.Printf(&quot;request body=%s\n&quot;, body)
var data TodoBody
if err := json.Unmarshal(body, &amp;data); err != nil {
log.Println(err)
}
// userId := 12
todo := data.Todo
todoData := Todo{todo, time.Now(), time.Now()}
_, err2 := auth.TokenVerify(tokenString)
if err2 != nil {
log.Fatal(err)
} else {
stmt, err := db.Prepare(&quot;INSERT INTO todos (Todo,CreatedAt,UpdatedAt) VALUES(?,?,?)&quot;)
if err != nil {
log.Fatal(err)
}
_, err = stmt.Exec(todoData.Todo, todoData.CreatedAt, todoData.UpdatedAt)
if err != nil {
log.Fatal(err)
}
json.NewEncoder(w).Encode(todoData)
}
}

React Frontend

import { useState } from &quot;react&quot;;
import { useCreateTodo } from &quot;../../hooks/useCreateTodo&quot;;
import { BaseButton } from &quot;../atoms/baseButton&quot;;
import { TextArea } from &quot;../atoms/textArea&quot;;
export const AddTodo = () =&gt; {
const [text, setText] = useState(&quot;&quot;);
const CreateTodo = useCreateTodo();
const token = &quot;Bearer &quot; + sessionStorage.getItem(&quot;token&quot;);
const onClickCreate = () =&gt; {
CreateTodo(token, text);
};
return (
&lt;div&gt;
&lt;TextArea
onChange={(e: any) =&gt; setText(e.target.value)}
defaultValue=&quot;&quot;
/&gt;
&lt;BaseButton text=&quot;タスクを追加&quot; onClick={onClickCreate} /&gt;
&lt;/div&gt;
);
};

POST here ↓

import axios from &quot;axios&quot;;
export const useCreateTodo = () =&gt; {
const CreateTodo = (token: string, todo: any) =&gt; {
const URL = &quot;http://127.0.0.1:8080/createtodo&quot;;
const data = { todo: todo };
console.log(data);
axios
.post(URL, JSON.stringify(data), { headers: { Authorization: token } })
.then((res) =&gt; console.log(res))
.catch((err) =&gt; console.log(err));
};
return CreateTodo;
};

If I don't add a header when POST the correct value comes to Go's ioutil.ReadAll(r.Body), but if I add a header, I can't get the value.
When I hit Go's API with the Advanced REST client, it is processed correctly even with the header information, so I am wondering if there is a problem with the POST method, but I can't seem to solve the problem.
I would be grateful for your help. Best regards.

答案1

得分: 1

我添加了这段代码,问题得到了解决。

w.Header().Set("Access-Control-Allow-Origin", "http://localhost:3000")
	switch r.Method {
	case "OPTIONS":
		w.Header().Set("Access-Control-Allow-Headers", "*")
		w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
		return

感谢您的合作!

英文:

I added this code and it solved the problem..

w.Header().Set(&quot;Access-Control-Allow-Origin&quot;, &quot;http://localhost:3000&quot;)
switch r.Method {
case &quot;OPTIONS&quot;:
w.Header().Set(&quot;Access-Control-Allow-Headers&quot;, &quot;*&quot;)
w.Header().Set(&quot;Access-Control-Allow-Methods&quot;, &quot;GET, POST, OPTIONS&quot;)
return

Thanks for your cooperation!

huangapple
  • 本文由 发表于 2022年6月23日 01:06:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/72719437.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定