Preflight 未通过控制检查 Access-Control-Allow-Origin Not Present

Posted

技术标签:

【中文标题】Preflight 未通过控制检查 Access-Control-Allow-Origin Not Present【英文标题】:Preflight Doesn't Pass Control Check Access-Control-Allow-Origin Not Present 【发布时间】:2018-02-09 15:21:38 【问题描述】:

我有一个在 React 中运行的简单客户端。我正在尝试使用 Axios 向本地运行的 Go 服务器发出 GET 请求。 React 代码在 3000 端口上运行,Go 服务器在 4000 上运行。

如果我将 GET 请求本身粘贴到浏览器窗口中,它可以正常工作:http://localhost:4000/numberconverter?number=10&oldBase=10&newBase=2

我做了一些研究并找到了this post,但插件和 Chrome 选项没有帮助。这不是我做过的唯一研究,但这似乎是最有希望的。我发现的大多数东西都不涉及 Go 服务器。

我也找到了this post,但这也没有解决我的问题。如果我取消注释服务器中的代码,它仍然会失败。

如果我将允许的方法更改为:

writer.Header().Set("Access-Control-Allow-Methods", "GET, POST, PATCH, PUT, DELETE, OPTIONS")

失败并出现 405 错误。服务器打印出这个:

&0xc4200f4000 0xc42000a500  0x10ec430 true false false false 0xc4200143c0 0xc420100000 map[Access-Control-Allow-Origin:[*] Access-Control-Allow-Methods:[GET, POST, PATCH, PUT, DELETE, OPTIONS] Content-Type:[text/plain; charset=utf-8] X-Content-Type-Options:[nosniff]] false false map[Access-Control-Allow-Origin:[*] Access-Control-Allow-Methods:[GET, POST, PATCH, PUT, DELETE, OPTIONS] Content-Type:[text/plain; charset=utf-8] X-Content-Type-Options:[nosniff]] true 19 -1 405 false false [] 0 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0] 0xc4200620e0 0

我想我的问题是这是服务器端还是客户端的问题,以及我该如何解决这个问题?

客户:

import React, Component from 'react';
import axios from 'axios';

class Converter extends Component 
    constructor(props) 
        super(props);
        this.state = 
            // number: 0,
            // base: 10,
            // newBase: 10
        ;
        this.convertButtonPressed = this.convertButtonPressed.bind(this);
        this.handleChange = this.handleChange.bind(this);
    

    handleChange(event) 
        const target = event.target;
        const value = target.value;
        const name = target.name;

        this.setState(
        [name]: value
        );
    

    convertButtonPressed(event) 
        axios(
            method: 'GET',
            baseURL: 'http://localhost:4000/',
            url: '/numberconverter',
            headers: 
                'Access-Control-Allow-Origin': '*',
                'Access-Control-Allow-Methods': 'GET, POST, PATCH, PUT, DELETE, OPTIONS',
                'Access-Control-Allow-Headers': 'Origin, Content-Type, X-Auth-Token'
            ,
            params: 
            number: this.state.number,
            oldBase: this.state.base,
            newBase: this.state.newBase
            
        );
    

    render() 
        return (
        <div className="App">
            <p>Number Converter</p>
            <div>
            Number:
            <input name="number" onChange=this.handleChange type="text" placeholder="Number"></input><br />
            Base:
            <input name="base" onChange=this.handleChange type="text" placeholder="Base"></input><br />
            New Base:
            <input name="newBase" onChange=this.handleChange type="text" placeholder="New Base"></input><br />
            </div>
            <button onClick=this.convertButtonPressed>Convert</button>
        </div>
        );
    


export default Converter;

服务器:

package rest

// Example:
// http://localhost:3000/numberconverter?number=500000&oldBase=10&newBase=16

import (
    "fmt"
    "log"
    "net/http"

    "../converter"
)

// Start starts the server
func Start() 
    //muxRouter := http.NewServeMux()
    //muxRouter.HandleFunc("/numberconverter", numberconverter)
    //http.Handle("/", muxRouter)
    http.HandleFunc("/numberconverter", numberconverter)
    log.Fatal(http.ListenAndServe(":4000", nil))


func numberconverter(writer http.ResponseWriter, response *http.Request) 
    //writer.Header().Set("Access-Control-Allow-Origin", "*")
    //writer.Header().Set("Access-Control-Allow-Methods", "*")
    //writer.Header().Set("Content-Type", "text/html; charset=utf-8")

    // Check if the method is a get
    if response.Method != http.MethodGet 
        http.Error(writer, http.StatusText(405), 405)
        fmt.Println(writer)
        return
    

    number := response.FormValue("number")
    oldBase := response.FormValue("oldBase")
    newBase := response.FormValue("newBase")
    result := converter.ConvertStringNumberToNewBase(number, oldBase, newBase)
    fmt.Fprintf(writer, "%s base %s is %s in base %s", number, oldBase, result, newBase)

【问题讨论】:

取消注释这些标题设置行是否有效?浏览器扩展绝对是解决这个问题的错误方法。您的任何用户都不会拥有它们。 IIRC,Access-Control-Allow-Methods 不能是 *。它应该是一个方法列表。 Setting HTTP headers的可能重复 @captncraig 如果我取消注释这些行,它仍然不起作用。这些行来自我试图解决问题。 您的前端代码添加的那些标头会触发您的浏览器在尝试 GET 请求之前自动执行 COR preflight OPTIONS 请求,您的代码打算发送 developer.mozilla.org/en-US/docs/Web/HTTP/… 并且因为在后端代码中您将请求发送到的服务器,您有它执行if response.Method != http.MethodGet http.Error(writer, http.StatusText(405), 405) …,当浏览器发送预检选项并且预检失败并且您的浏览器永远不会继续尝试从您的代码中获取 GET 时,它会被命中 【参考方案1】:

一旦我注释掉 React 代码中的标头,GET 请求就会起作用。我要感谢sideshowbarker 的回答。我真的很感激。

convertButtonPressed(event) 
    axios(
        method: 'GET',
        baseURL: 'http://localhost:4000/',
        url: '/numberconverter',
        // headers: 
        //     'Access-Control-Allow-Origin': '*',
        //     'Access-Control-Allow-Methods': 'GET, POST, PATCH, PUT, DELETE, OPTIONS',
        //     'Access-Control-Allow-Headers': 'Origin, Content-Type, X-Auth-Token'
        // ,
        params: 
          number: this.state.number,
          oldBase: this.state.base,
          newBase: this.state.newBase
        
      );

【讨论】:

以上是关于Preflight 未通过控制检查 Access-Control-Allow-Origin Not Present的主要内容,如果未能解决你的问题,请参考以下文章

对预检请求的响应未通过访问控制检查:“Access-Control-Allow-Origin”标头包含多个值

对预检请求的响应未通过访问控制检查:响应中“Access-Control-Allow-Credentials”标头的值为“”

离子视图 - 对预检请求的响应未通过访问控制检查:没有“Access-Control-Allow-Origin”标头

获取请求未通过访问控制检查:请求的资源上不存在“Access-Control-Allow-Origin”标头

Angular 6 - 对预检请求的响应未通过访问控制检查:没有“Access-Control-Allow-Origin”标头

错误 - 预检请求未通过访问控制检查:请求的资源上不存在“Access-Control-Allow-Origin”标头