我最近部署的云函数面临 CORS 错误,即使我在代码中包含了
Access-Control-Allow-Origin: *
:
package controllers
import (
"encoding/json"
"fmt"
"net/http"
"cloud.google.com/go/firestore"
"cloud.google.com/go/logging"
"github.com/Task3/models"
"github.com/Task3/validations"
)
func CreateEmployee(w http.ResponseWriter, r *http.Request) {
mu.Lock()
defer mu.Unlock()
var employee models.Employee
err := json.NewDecoder(r.Body).Decode(&employee)
if err != nil {
w.Header().Set("Content-Type", "text/plain")
http.Error(w, "Invalid JSON", http.StatusBadRequest)
logger.Log(logging.Entry{
Payload: "Invalid JSON input for type Employee during controllers.CreateEmployee function call.",
Severity: logging.Error,
})
w.Header().Set("Content-Type", "application/json")
return
}
err1 := validations.V.Struct(employee)
if err1 != nil {
w.Header().Set("Content-Type", "text/plain")
http.Error(w, "Invalid input for employee deatails\n-First name must contain alphabets or spaces only.\n-First name must contain alphabets or spaces only.\n-Email id must be valid eg. [email protected].\n-Password must be atleast 6 charecters long.\n-Phone no. should be valid.\n-Role must be either of - 'admin', 'developer', 'manager', 'tester'. (case sensetive)\n-Salary must be a number.\n-Birthdate should be in yyyy-mm-dd format.", http.StatusUnprocessableEntity)
logger.Log(logging.Entry{
Payload: fmt.Sprintf("Invalid employee data input : occured while validating employee fields during controllers.CreateEmployee function call.\n%v", err1),
Severity: logging.Error,
})
w.Header().Set("Content-Type", "application/json")
return
}
// Query to get the maximum employee ID
iter := client.Collection("ems").OrderBy("ID", firestore.Desc).Limit(1).Documents(ctx)
var lastEmployee models.Employee
for {
doc, err := iter.Next()
if err != nil {
break
}
doc.DataTo(&lastEmployee)
// break
}
// Generate new employee ID
EmpId := lastEmployee.ID + 1
employee.ID = EmpId
// Save employee data to Firestore
_, _, err = client.Collection("ems").Add(ctx, employee)
if err != nil {
logger.Log(logging.Entry{
Payload: "Failed to create employee",
Severity: logging.Error,
})
w.Header().Set("Content-Type", "text/plain")
http.Error(w, "Failed to create employee", http.StatusInternalServerError)
return
}
// Setting headers and staus codes
// Set CORS headers for all requests
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
// Handle preflight request
if r.Method == http.MethodOptions {
w.WriteHeader(http.StatusNoContent)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(employee)
logger.Log(logging.Entry{
Payload: fmt.Sprintf("Employee created successfully with emp id %v", EmpId),
Severity: logging.Info,
})
}
它适用于 Postman,但不适用于除 Postman 之外的其他客户端。
我通过为 CORS 添加适当的标头来部署我的云函数,但每当我尝试调用我的函数时,它仍然会给我一个 CORS 失败错误。
尽管 GCF 文档告诉您什么,手动实现 CORS 并不是一个好主意,因为它很容易出错。恰当的例子:Google Cloud 的 Go 示例将所有
OPTIONS
请求错误分类为 CORS 预检请求;有关此主题的更多信息,请参阅我的一篇博客文章。
相反,依赖 CORS 中间件库几乎总是更好。例如,这是使用我自己的库jub0bs/fcors:
配置为 CORS 的第一代基于 Go 的 Google Cloud Function 的概念证明package p
import (
"fmt"
"log"
"net/http"
"github.com/jub0bs/fcors"
)
var Handler func(w http.ResponseWriter, r *http.Request)
func init() {
cors, err := fcors.AllowAccess(
fcors.FromAnyOrigin(),
fcors.WithMethods(http.MethodPost),
fcors.WithRequestHeaders("Content-Type"),
)
if err != nil {
log.Fatal(err)
}
Handler = cors(http.HandlerFunc(HelloWorld)).ServeHTTP
}
func HelloWorld(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello World!")
}
这是第二代 GCF 的等效概念证明:
package helloworld
import (
"fmt"
"log"
"net/http"
"github.com/GoogleCloudPlatform/functions-framework-go/functions"
"github.com/jub0bs/fcors"
)
func init() {
cors, err := fcors.AllowAccess(
fcors.FromAnyOrigin(),
fcors.WithMethods(http.MethodPost),
fcors.WithRequestHeaders("Content-Type"),
)
if err != nil {
log.Fatal(err)
}
handler := cors(http.HandlerFunc(HelloWorld)).ServeHTTP
functions.HTTP("HelloHTTP", handler)
}
func HelloWorld(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello World!")
}
当然,无论您选择第一代还是第二代 GCF,您还需要充分填充
go.mod
和 go.sum
文件:
module example.com/cloudfunction
go 1.21
require github.com/jub0bs/fcors v0.7.0
require (
golang.org/x/net v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
)
github.com/jub0bs/fcors v0.7.0 h1:UVG2J1Nj+tvnYhj1BpMNR586CEEVmyDP7M2A6B4TErI=
github.com/jub0bs/fcors v0.7.0/go.mod h1:0jIYAcJa59RHDHwB+UZ64tcAbX3qU1V9xgH4nZoVDBs=
golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg=
golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=