CORS策略不允许并阻止从角度前端POST到Golang后端方法



我正试图从我的Angular前端向我的Golang后端发出一个post请求,两者都来自同一台机器。我不断得到:

OPTIONS http://localhost:12345/anteroom 405 (Method Not Allowed)

Access to XMLHttpRequest at 'http://localhost:12345/anteroom' from origin 'http://localhost:4200' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

Golang后端,使用Gorilla mux路由器:

func main() {
router := mux.NewRouter()
router.HandleFunc("/anteroom", anteroom).Methods("POST")
log.Fatal(http.ListenAndServe(":12345", router))
}
func anteroom(res http.ResponseWriter, req *http.Request) {
res.Header().Set("Access-Control-Allow-Origin", "*")
// *Edit 17 Jan 19 12.44pm*: Billy, user268396, and Peter suggest that OPTIONS should be added. As mentioned below, I've already tried that.
res.Header().Set("Access-Control-Allow-Methods", "POST")
res.Header().Set("Content-Type", "application/json")
// Put it into a struct variable and print a bit of it.
_ = json.NewDecoder(req.Body).Decode(&member)
fmt.Println(member.ID)
}

角度前端组件:

export class AnteroomComponent implements OnInit {
public profile: string;
constructor(private http: HttpClient, private cookieService: CookieService) {}
ngOnInit() {}
// This is the relevant function.
// Triggered by a button.
sendProfile(Profile) {
let httpHeaders = new HttpHeaders({
"Content-Type": "application/json",
"Origin": "http://localhost:4200"
});
return this.http
.post("http://localhost:12345/anteroom", this.profile, {
headers: httpHeaders,
observe: "response"
})
.subscribe(
data => {
console.log("POST Request is successful ", data);
},
error => {
console.log("Error", error);
}
);
}
}

以下是我尝试过的许多方法:

  • 我读到浏览器的工作是设置标题,而不是我的(这对我来说没有意义,因为HttpHeaders()是干什么的?),所以我从Angular中删除了所有标题。

  • 我尝试在果朗启用CORS,如下所示:

    (*w).Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
    if (*req).Method == "OPTIONS" {
    return
    }
    
  • 我尝试将Access-Control-Allow-Origin*更改为Origin,因为我在某个地方读到*阻止发送/接收cookie。(丢失了链接。)也许它也阻止了其他MIME类型?我不知道,只是尝试。

  • Mozilla说:"构造函数初始化一个XMLHttpRequest。它必须在任何其他方法调用之前被调用。"所以我想我会这么做,但Angular说:"@Angular/common/htt中的HttpClient为Angular应用程序提供了一个简化的客户端http API,该客户端基于浏览器公开的XMLHttpRequest接口。"所以,我想这不是必要的吗?构造函数已经包含HttpClient

  • 作为JSON:{id: testid, username: "Mr Odour", age: "87"}this.Profile看起来相当标准。但也许这就是问题所在。所以我把它放进String()。然后我用Golang的httputil.DumpRequest():从前端丢弃了响应

    output, err := httputil.DumpRequest(req, true)
    if err != nil {
    fmt.Println("Error dumping request:", err)
    return
    }
    fmt.Println(string(output))
    

    这也许提供了更多的见解。打印出来:

    POST /anteroom HTTP/1.1
    Host: localhost:12345
    Accept: application/json, text/plain, */*
    Accept-Encoding: gzip, deflate, br
    Accept-Language: en-US,en;q=0.9,en-GB;q=0.8
    Connection: keep-alive
    Content-Length: 15
    Content-Type: text/plain
    Dnt: 1
    Origin: http://localhost:4200
    Referer: http://localhost:4200/anteroom
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML,
    like Gecko) Chrome/71.0.3578.98 Safari/537.36
    

我觉得它成功了?我不确定。它没有说200 OK。控制台确实打印"POST请求成功",但没有data。我试着在Golang读到这个:

body, err := ioutil.ReadAll(req.Body)
if err != nil {
fmt.Println(err)
}
fmt.Println(body)

这产生了CCD_ 14。空的

它还说Content-Type: text/plain。这就是问题所在吗?不应该是application/json吗?但其他人的代码使用它的方式,没有String(),就像这样:

return this.http.post<Article>(this.url,
{
id: 100, 
title: 'Java Functional Interface', 
category: 'Java 8', 
writer: 'Krishna'
}
);
  • 编辑17 Jan 19下午12:45:Billy建议使用Header().Add()而不是Header().Set(),如下所示:

    res.Header().Add("Access-Control-Allow-Origin", "*")
    res.Header().Add("Access-Control-Allow-Methods", "POST")
    res.Header().Add("Access-Control-Allow-Methods", "OPTIONS")
    res.Header().Add("Content-Type", "application/json")
    

    所以,我做到了。也没用。

后端似乎还可以。我用curl贴到它上,它产生了:

Connected to localhost (::1) port 12345 (#0)
> POST /anteroom HTTP/1.1
> Host: localhost:12345
> User-Agent: curl/7.47.1
> Accept: */*
> Content-Type: application/json
> Content-Length: 126
>
} [126 bytes data]
* upload completely sent off: 126 out of 126 bytes
< HTTP/1.1 200 OK
*Edit 17 Jan 19 12.45pm*: Methods contains OPTIONS once the header is set in backend. So, no problem with curl this way.
< Access-Control-Allow-Methods: POST
< Access-Control-Allow-Origin: *
< Date: Tue, 15 Jan 2019 19:34:32 GMT
< Content-Length: 0

它还打印出fmt.Println(member.ID)和JSON字符串中的其他内容。

编辑19年1月17日下午13点25分:当我发布curl -i -X OPTIONS http://localhost:12345/anteroom时,它会返回:"访问控制允许方法:POST,OPTIONS"。因此OPTIONS正在发挥作用。但前端请求保持不变,没有明确的200 OK,即使控制台将其记录为成功,JSON似乎也不会通过。MIME类型在响应中被列为"text/plain",但这对JSON来说不好吗?如前所述,其他解决方案使用相同的格式,并且对它们有效。我现在正在处理这部分问题。

我是Golang、TypeScript和Angular的新手,所以我希望我能发布所有相关的代码。这似乎是一个流行的问题,所以我在这里看了很多类似的问题,但仍然无法弄清楚。我到底错过了什么?

这不是在后端执行CORS的方式。您的后端需要监听HTTPOPTIONS类型的请求,并在那里发送CORS头。

控制流程大致为:

  1. 你在前端请求一些东西
  2. 浏览器确定:哦,这需要CORS
  3. 浏览器首先对请求的资源执行OPTIONS请求以协商CORS
  4. 根据结果,任一浏览器都会向前端抛出错误
  5. 或者它继续执行您的前端发出的实际请求
  6. 从现在开始一切正常
  7. 当浏览器得到实际API回调的结果时,它会过滤掉步骤3和4中未列入白名单/协商的内容
  8. 它将潜在的审查结果作为HTTP调用的结果呈现给前端

问题的解决在很大程度上要感谢所有帮助我意识到我没有正确执行CORS的人。基本上有两个问题:1。我不知道如何在后场正确地设置头球,还有2个。我没有正确格式化JSON数据。

我注意到这是Stack Overflow上一个相当流行的问题,部分原因可能是我们中的一些人并不真正了解请求是如何工作的。因此,这里有一个总结,来自Mozilla宝贵的、简单的书面文档和用户268396的输入。我是新手,所以如果我错了,请纠正我。

通常情况下,这很简单:当你想请求某个内容时,浏览器会根据你已经拥有的内容设置适当的标题,并发送请求。服务器响应。

但是,假设您在后端有一个API POST端点,在同一个域上有一个前端(我想我们大多数人都在开发中,但可能不是在生产中),并且您使用的是application/x-www-form-urlencoded、multipart/form-data和text/plain之外的任何东西,那么这就有点不同了。在我的例子中,我使用的是application/json。看起来是这样的:

  1. Browser使用OPTIONS方法发送请求,询问允许的方法和内容类型以及其他内容。这被称为飞行前请求。它还没有发送我的JSON对象。

  2. 服务器响应飞行前请求。

为了让服务器用允许的东西进行响应,我们需要在Access Control allow Methods中正确设置后端以允许OPTIONS方法,如果你像我一样使用Gorilla mux,请记住在router.HandleFunc()中也允许它。

因为我们的前端和后端在同一个域上(http://localhost),最简单的方法是将Access Control Allow Origin设置为"*"。然而,根据我们的需求,我们可能不想在生产中这样做,因为*意味着全世界和其他地方都可以发送请求。

因为我想接收JSON,所以我还在后端将ContentType设置为application/JSON。这是我问题的另一半。长话短说,无论什么对其他人有效,出于某种原因,我仍然必须将JSON.stringify()应用于我的原始JSON数据。然后它完美地工作了。

  1. 一旦浏览器收到允许的OPTIONS,它就会过滤掉不允许的内容,并只发送一个包含适当数据的请求。在我的情况下,这将是JSON对象

就这样。

@user268396告诉过你为什么,我会告诉你怎么做。

"Access-Control-Allow-Origin"表示您允许向该服务器发出请求的来源。

它可以是以下形式:

  • "*">
  • "https://github.com">
  • "http://127.0.0.1:8080">
  • "镀铬加长件://*">
  • "*.some domain.com">

当您想要从CORS发布数据时,"Access-Control-Allow-Methods"应该是[]字符串("POST","OPTION")。

当它来到戈兰,见godochttps://golang.org/pkg/net/http/#Header

type Header map[string][]string

我总是建议使用Header.Add()而不是Header.Set(),除非你确切地知道自己在做什么。因为标头中的每个值总是[]字符串。

所以应该是

res.Header().Add("Access-Control-Allow-Origin", "*")
res.Header().Add("Access-Control-Allow-Methods", "POST")
res.Header().Add("Access-Control-Allow-Methods", "OPTION")
res.Header().Add("Content-Type", "application/json")

相关内容

最新更新