如何解决Google Cloud Functions中的CORS跨域问题?
解决Google Cloud Function中Go代码的CORS错误问题
你的问题核心在于CORS头设置时机错误,以及错误分支未返回CORS头,导致浏览器的跨域请求(包括预请求OPTIONS)无法通过校验。Postman不受浏览器同源策略限制,所以能正常工作,但浏览器客户端会触发CORS校验失败。
问题根源
- CORS头设置太晚:当前代码在业务逻辑执行完成后才设置CORS头,而浏览器发送的OPTIONS预请求会先到达函数,此时还没执行到设置头的代码,导致OPTIONS响应没有CORS头,直接触发错误。
- 错误分支无CORS头:当JSON解析失败、参数验证错误、Firestore写入失败时,你直接返回了错误响应,但这些响应里没有包含CORS头,浏览器会因为缺少允许跨域的头而拒绝接收响应。
修复方案
把CORS头的设置放在函数最开头,优先处理OPTIONS请求,确保所有请求(包括错误响应)都携带CORS头。
修复后的代码
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) { // 先设置所有CORS头,确保所有响应都携带 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") // 优先处理OPTIONS预请求,直接返回204 if r.Method == http.MethodOptions { w.WriteHeader(http.StatusNoContent) return } 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. abc@example.com.\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) } // 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 } 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, }) }
关键修改说明
- 提前设置CORS头:函数执行最开始就设置所有CORS相关响应头,确保无论是成功响应还是错误响应,都携带允许跨域的头。
- 优先处理OPTIONS请求:在任何业务逻辑执行前,先检查并处理OPTIONS预请求,直接返回204状态码,避免预请求进入业务逻辑流程。
内容的提问来源于stack exchange,提问作者Shreyas Awankar
相关产品推荐
相关产品推荐

