在 Golang 中启用 CORS



嗨,我正在实现 rest APIS,为此我想允许提供跨源请求。

我目前正在做什么:

AWS 上的 Go 服务器代码:

func (c *UserController) Login(w http.ResponseWriter, r *http.Request, ctx *rack.Context) {
w.Header().Set("Access-Control-Allow-Origin", r.Header.Get("Origin"))
w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
...
...
c.render.Json(w,rsp, http.StatusOK)
return
}

本地主机上的 Ajax 代码:

<script>
$( document ).ready(function() {
    console.log( "ready!" );
    $.ajax({
        url: 'http://ip:8080/login',
        crossDomain: true, //set as a cross domain requests
        withCredentials:false,
        type: 'post',
        success: function (data) {
            alert("Data " + data);
        },
    });
});

我在浏览器控制台上收到以下错误:XMLHttpRequest 无法加载 http://ip:8080/login。请求的资源上不存在"访问控制允许源"标头。因此,不允许访问源"http://localhost:8081"。响应具有 HTTP 状态代码 422。

我尝试添加印前检查选项:

func corsRoute(app *app.App) {
allowedHeaders := "Accept, Content-Type, Content-Length, Accept-Encoding, Authorization,X-CSRF-Token"
f := func(w http.ResponseWriter, r *http.Request) {
    if origin := r.Header.Get("Origin"); origin != "" {
        w.Header().Set("Access-Control-Allow-Origin", "*")
        w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
        w.Header().Set("Access-Control-Allow-Headers", allowedHeaders)
        w.Header().Set("Access-Control-Expose-Headers", "Authorization")
    }
    return
}
app.Router.Options("/*p", f, publicRouteConstraint)
}

但它不起作用。

可以做些什么来修复它。

我使用gorilla/mux包来构建Go RESTful API服务器,客户端使用JavaScript请求可以工作,

My Go Server 运行在 localhost:9091 ,服务器代码:

router := mux.NewRouter()
//api route is /people, 
//Methods("GET", "OPTIONS") means it support GET, OPTIONS
router.HandleFunc("/people", GetPeopleAPI).Methods("GET", "OPTIONS")
log.Fatal(http.ListenAndServe(":9091", router))

我发现在这里给出OPTIONS很重要,否则会发生错误:

选项 http://localhost:9091/people 405(方法不允许(

无法加载 http://localhost:9091/people:对预检请求的响应未通过访问控制检查:请求的资源上不存在"访问控制允许源"标头。因此,不允许访问源"http://localhost:9092"。响应的 HTTP 状态代码为 405。

允许后OPTIONS它工作得很好。我从这篇文章中得到了这个想法。

此外,MDN CORS文档提到:

此外,对于可能对服务器数据造成副作用的 HTTP 请求方法,规范要求浏览器"预检"请求,使用 HTTP OPTIONS 请求方法从服务器请求支持的方法,然后在服务器"批准"后,使用实际的 HTTP 请求方法发送实际请求。

以下是 api GetPeopleAPI 方法,注意在我给出注释的方法中//允许 CORS 在这里通过 * 或特定来源,我还有另一个类似的答案在这里解释 CORS 的概念:

func GetPeopleAPI(w http.ResponseWriter, r *http.Request) {
    //Allow CORS here By * or specific origin
    w.Header().Set("Access-Control-Allow-Origin", "*")
    w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
    // return "OKOK"
    json.NewEncoder(w).Encode("OKOK")
}

在客户端中,我在 localhost:9092 上使用 html 和 javascript,javascript 会从 localhost:9092 向服务器发送请求

function GetPeople() {
    try {
        var xhttp = new XMLHttpRequest();
        xhttp.open("GET", "http://localhost:9091/people", false);
        xhttp.setRequestHeader("Content-type", "text/html");
        xhttp.send();
        var response = JSON.parse(xhttp.response);
        alert(xhttp.response);
    } catch (error) {
        alert(error.message);
    }
}

并且请求可以成功获得响应"OKOK"

您还可以通过 Fiddler 等工具检查响应/请求标头信息。

感谢您的线索 - 这一切都在标题中!我在服务器端只使用这些 golang 标头:

w.Header().Set("Content-Type", "text/html; charset=utf-8")
w.Header().Set("Access-Control-Allow-Origin", "*")

现在使用此 JQuery:

<script 
src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js">
</script>
<script>
$.ajax({
    type: 'GET',
    url: 'https://www.XXXXXXX.org/QueryUserID?u=juXXXXny&p=blXXXXXne',
    crossDomain: true,
    dataType: 'text',
    success: function(responseData, textStatus, jqXHR) {
        alert(responseData);
            },
    error: function (responseData, textStatus, errorThrown) {
        alert('POST failed.');
    }
});
</script>

你可以看看这个 https://github.com/rs/cors

这也将处理Options请求

GO 服务器设置:

package main
import (
  "net/http"
)

  func Cors(w http.ResponseWriter, r *http.Request) {
  w.Header().Set("Content-Type", "text/html; charset=ascii")
  w.Header().Set("Access-Control-Allow-Origin", "*")
  w.Header().Set("Access-Control-Allow-Headers","Content-Type,access-control-allow-origin, access-control-allow-headers")
          w.Write([]byte("Hello, World!"))
  }
  func main() {
  mux := http.NewServeMux()
  mux.HandleFunc("/plm/cors",Cors)
  http.ListenAndServe(":8081", mux)
}

客户端 JQUERY AJAX 设置:

<head>
       <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js">
       </script>
</head>
<body>
              <br> Please confirm to proceed : <button class="myConfirmButton1">Go!!</button>
             <div id="loader1" style="display:none;">loading...</div>
             <div id="loader2" style="display:none;">...done</div>
             <div id="myFeedback1"></div>
          <script>
          $(document).ready(function(){
            $(".myConfirmButton1").click(function(){
              $('#loader1').show();
              $.ajax({
                url:"http://[webserver.domain.com:8081]/plm/cors",
                dataType:'html',
                headers: {"Access-Control-Allow-Origin": "*", "Access-Control-Allow-Headers": "access-control-allow-origin, access-control-allow-headers"},
                type:'get',
                contentType: 'application/x-www-form-urlencoded',
                success: function( data, textStatus, jQxhr ){
                $('#loader1').hide();
                $('#loader2').show();
                $('#myFeedback1').html( data );
                        },
                error: function( jqXhr, textStatus, errorThrown ){
                $('#loader1').hide();
                $('#myFeedback1').html( errorThrown );
                alert("error" + errorThrown);
                        }
                });
           });
          });
          </script>
</body>

带有 curl 的客户端测试请求并获得的响应:

curl -iXGET http://[webserver.domain.com:8081]/plm/cors

HTTP/1.1 200 OK
Access-Control-Allow-Headers: Content-Type,access-control-allow-origin, access-control-allow-headers
Access-Control-Allow-Origin: *
Content-Type: text/html; charset=ascii
Date: Wed, 17 Jan 2018 13:28:28 GMT
Content-Length: 13
Hello, World!

为了允许 CORS,您的服务器应该捕获浏览器在使用 OPTIONS 方法进行实际查询之前发送到同一路径的所有印前检查请求。

第一种方法是通过这样的东西手动管理它:

func setupCORS(w *http.ResponseWriter, req *http.Request) {
    (*w).Header().Set("Access-Control-Allow-Origin", "*")
    (*w).Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
    (*w).Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
}
func indexHandler(w http.ResponseWriter, req *http.Request) {
    setupCORS(&w, req)
    if (*req).Method == "OPTIONS" {
        return
    }
    // process the request...
}

第二种方法是使用准备好的第三方 pkg,如 https://github.com/rs/cors

package main
import (
    "net/http"
    "github.com/rs/cors"
)
func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Content-Type", "application/json")
        w.Write([]byte("{"hello": "world"}"))
    })
    // cors.AllowAll() setup the middleware with default options being
    // all origins accepted with simple methods (GET, POST). See
    // documentation below for more options.
    handler := cors.AllowAll().Handler(mux)
    http.ListenAndServe(":8080", handler)
}

添加到所有伟大的答案:而不是在每个处理程序中设置标头,您可能希望使用 appHandler 模式:

type Handler func(http.ResponseWriter, *http.Request) *Error
func (fn Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Access-Control-Allow-Origin", "*")
    w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
    if e := fn(w, r); e != nil { // e is *appError, not os.Error.
        http.Error(w, e.Message, e.Code)
    }
}
func Login(w http.ResponseWriter, r *http.Request) *Error {
   ...
   return nil
}
r.Handle("/login", Handler(Login))
好的,

这个问题给了我一些问题,但找到了您必须使用的修复程序

github.com/gorilla/handlers

连同 Gollila/mux lib

所以这里有一个片段

r := mux.NewRouter()
header := handlers.AllowedHeaders([]string{"X-Requested-With", "Content-Type", "Authorization"})
methods := handlers.AllowedMethods([]string{"GET", "POST", "PUT", "HEAD", "OPTIONS"})
origins := handlers.AllowedOrigins([]string{"*"})
api := r.PathPrefix("/api").Subrouter()
api.Handle("/route", function).Methods("GET", "OPTIONS")
r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    _, _ = fmt.Fprint(w, "hello")
})
err := http.ListenAndServe(":9000", handlers.CORS(header, methods, origins)(r))
if err != nil {
    fmt.Println(err)
}

这应该可以解决您的问题

  1. 第一:科斯

    svc.Handle("/", restAPI.Serve(nil))
    
  2. 之后,我修复:句柄 ->句柄函数

    svc.HandleFunc("/", func(rw http.ResponseWriter, req *http.Request) {
         setupHeader(rw, req)
         if req.Method == "OPTIONS" {
             rw.WriteHeader(http.StatusOK)
             return
         }
         restAPI.Serve(nil).ServeHTTP(rw, req)
         return
     })
    
     func setupHeader(rw http.ResponseWriter, req *http.Request) {
            rw.Header().Set("Content-Type", "application/json")
            rw.Header().Set("Access-Control-Allow-Origin", "*")
            rw.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
            rw.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
    }
    

我最近遇到了同样的问题。 我发现仅设置Access-Control-Allow-Origin并不能解决我的问题。 我遇到的问题是浏览器首先发送OPTIONS请求

所以我不得不检查OPTIONS请求并发送 OK 响应来解决此问题。 这样做实际上解决了我大部分与 CROS 相关的问题。

下面列出了我如何做的示例代码

<小时 />

这是我的服务器端中间件,负责处理所有CROS相关的事情

func CORSMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Access-Control-Allow-Origin", "*") // change this later
        w.Header().Set("Access-Control-Allow-Credentials", "true")
        w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With")
        w.Header().Set("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS")
        if r.Method == "OPTIONS" {
            w.WriteHeader(204)
            return
        }
        next.ServeHTTP(w, r)
    })
}
<小时 />

对于我的前端,我通常使用React Framework。 下面是我创建帖子的示例代码。 以及我通常如何在前面使用它。

(也适用于我的表格,我在这里使用福米克(

  <Formik
              initialValues={{ title: "", slug: "" }}
              validate={(values) => {
                const errors = {};
                if (!values.title) {
                  errors.title = "Required";
                } else if (!values.slug) {
                  errors.slug = "Required";
                }
                return errors;
              }}
              onSubmit={(resp, { setSubmitting }) => {
                setTimeout(() => {
                  var encodedPost = btoa(value);
                  resp.post = encodedPost;
                  console.log(JSON.stringify(resp, null, 2));
                  const cookies = new Cookies();
                  let authtoken = cookies.get("auth");
                  /* sending the request */
                  var myHeaders = new Headers();
                  myHeaders.append("Authorization", `Bearer ${authtoken}`);
                  myHeaders.append("Content-Type", "application/json");
                  var requestOptions = {
                    method: "POST",
                    headers: myHeaders,
                    body: JSON.stringify(resp),
                  };
                  fetch(
                    "http://localhost:4000/api/v1/post/create",
                    requestOptions
                  )
                    .then((response) => response.json())
                    .then((result) => {
                      console.log(result);
                      alert(JSON.stringify(result, null, 2));
                    })
                    .catch((error) => {
                      alert(JSON.stringify(error, null, 2));
                    });
                  setSubmitting(false);
                }, 400);
              }}
            >
router := mux.NewRouter()
api := router.PathPrefix("/api/v1").Subrouter()
api.HandleFunc("/getLastDateOfAMonth", lastday.Handler).Methods(http.MethodPost)
c := cors.New(cors.Options{
    AllowedOrigins:   []string{"http://localhost:3000"},
    AllowCredentials: true,
    AllowedMethods:   []string{"GET", "DELETE", "POST", "PUT"},
})
handler := c.Handler(router)
log.Fatal(http.ListenAndServe(":3001", handler))

请检查此 -> https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request#:~:text=A%20CORS%20preflight%20request%20is,Headers%20%2C%20and%20the%20Origin%20header。

我们都面临CORS问题->修复 ->后端服务器应接受 CORS。将 cors 添加到后端应用程序。以便它了解来自浏览器的印前检查请求的 CORS。

相关内容

  • 没有找到相关文章

最新更新