ajax 在 Golang 中启用 CORS

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/39507065/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-06 10:30:57  来源:igfitidea点击:

Enable CORS in Golang

ajaxgocorscross-domain

提问by Yash Srivastava

Hi I'm implementing rest apis and for that I want to allow cross origin requests to be served.

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

What I am currently doing:

我目前在做什么:

Go-server code on AWS:

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 code on localhost:

本地主机上的 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);
        },
    });
});

I am getting the following error on browser console: XMLHttpRequest cannot load http://ip:8080/login. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8081' is therefore not allowed access. The response had HTTP status code 422.

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

I tried adding preflight options:

我尝试添加预检选项:

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)
}

But it is not working.

但它不起作用。

What can be done to fix it.

可以做些什么来修复它。

回答by yu yang Jian

I use gorilla/muxpackage to build Go RESTful API server, and client use JavaScript Request can work,

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

My Go Server runs at localhost:9091, and the Server code:

我的 Go 服务器运行在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))

I find giving OPTIONShere is important, otherwise error will occur:

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

OPTIONS http://localhost:9091/people405 (Method Not Allowed)

Failed to load http://localhost:9091/people: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:9092' is therefore not allowed access. The response had HTTP status code 405.

选项http://localhost:9091/people405(不允许的方法)

无法加载http://localhost:9091/people:对预检请求的响应未通过访问控制检查:请求的资源上不存在“Access-Control-Allow-Origin”标头。因此,不允许访问Origin ' http://localhost:9092'。响应具有 HTTP 状态代码 405。

after allow OPTIONSit works great. I get the idea from This Article.

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

Besides, MDN CORS docmention:

此外,MDN CORS 文档提到:

Additionally, for HTTP request methods that can cause side-effects on server's data, the specification mandates that browsers "preflight"the request, soliciting supported methods from the server with an HTTP OPTIONSrequest method, and then, upon "approval" from the server, sending the actual request with the actual HTTP request method.

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

Following is the api GetPeopleAPImethod, note in the method I give comment //Allow CORS here By * or specific origin, I have another similar answer explaining the concept of CORS Here:

以下是 api GetPeopleAPI方法,注意在我给出注释的方法中//Allow CORS here By * or specific origin,我有另一个类似的答案解释了 CORS Here的概念:

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")
}

In the client, I use html with javascript on localhost:9092, and javascript will send request to server from localhost:9092

在客户端,我使用 html 和 javascript on localhost:9092,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);
    }
}

and the request can successfully get response "OKOK".

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

You can also check response/request header information by tools like Fiddler.

您还可以通过诸如Fiddler.

回答by Gaurav Manchanda

You can check this out https://github.com/rs/cors

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

This would handle the OptionsRequest as well

这也将处理Options请求

回答by user2099484

Thanks for the clue - it's all in the header! I use only these golang headers on the server side:

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

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

Now works with this JQuery:

现在使用这个 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>

回答by Pascal Louis-Marie

GO SERVER SETTING :

进入服务器设置:

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)
}

Client JQUERY AJAX SETTING :

客户端 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>

Client TEST REQUEST with curl and obtained response :

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

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

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!

回答by Maxim

For allowing CORSyour server should to catch all Preflight requestthat's browser sends before real query with OPTIONS method to the same path.

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

First way is managing this manually by something like this:

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

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...
}

The second way is use ready to third party pkg like https://github.com/rs/cors

第二种方法是使用准备好的第三方 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.Default() setup the middleware with default options being
    // all origins accepted with simple methods (GET, POST). See
    // documentation below for more options.
    handler := cors.Default().Handler(mux)
    http.ListenAndServe(":8080", handler)
}

回答by user4920718

Ok this problem gave me some issues but found a fix u have to use

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

github.com/gorilla/handlers

along with the gollila/mux lib

与 gollila/mux 库一起使用

so here is a snippet

所以这是一个片段

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)
}

this should fix ur problem

这应该可以解决你的问题

回答by ET-CS

Adding to all the great answers: instead of setting the headers in every handler you probably want to use the appHandlerpattern:

添加所有很棒的答案:您可能想要使用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))