小能豆

Is there any way to get rid of CORS in gcp cloud functions?

go

I am facing the CORS error for a cloud function I recently deployed even though I have included “Access-Control-Allow-Origin”, “*” in my code.

Here is the code

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. 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)
        // 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,
    })

}

It works on postman but not on other clients than postman. Please suggest something…

I deployed my cloud function by adding appropriate headers for CORS but its still give me a CORS failure error whenever I try to invoke my function.


阅读 69

收藏
2023-12-18

共1个答案

小能豆

When working with Cloud Functions and CORS, you need to ensure that the response from your Cloud Function includes the necessary CORS headers. It seems you’ve set the headers for Access-Control-Allow-Origin, but you also need to handle the preflight OPTIONS request.

Here’s an updated version of your code to handle CORS correctly:

func CreateEmployee(w http.ResponseWriter, r *http.Request) {
    // ...

    // Setting headers
    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
    }

    // ...

    // Set content type and status code for the actual response
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(http.StatusCreated)
    json.NewEncoder(w).Encode(employee)

    // ...
}

In this modification, after setting the headers, it checks whether the incoming request is an OPTIONS request. If it is, the function returns an empty response with a StatusNoContent status code. This is a common pattern for handling preflight requests.

Make sure to deploy this updated function and test it again with your client. Also, keep in mind that browser-based clients, when making cross-origin requests, rely on the server returning the appropriate CORS headers, so they might behave differently compared to tools like Postman. If you’re still facing issues, consider checking the browser console for any error messages related to CORS.

2023-12-18