当试图从REST API获取数据时,请求的资源上没有'Access-Control-Allow-Origin'头。

我正试图从HP Alm的REST API中获取一些数据。用一个小的curl脚本工作得很好--我得到了我的数据。

现在用JavaScript、fetch和ES6(或多或少)来做,似乎是一个更大的问题。我一直收到这个错误信息。

Fetch API不能加载。对preflight请求的响应不'。 通过访问控制检查。No 'Access-Control-Allow-Origin'header is 存在于被请求的资源上。Origin 'http://127.0.0.1:3000' 是 因此不允许访问。响应有HTTP状态代码501。 如果不透明的响应符合你的需要,将请求的模式设置为 'no-cors'来获取禁用CORS的资源。

我明白,这是因为我试图从我的本地主机内获取该数据,解决方案应该是使用 CORS。现在我想我确实做到了,但不知怎的,它要么忽略了我在头文件中写的东西,要么问题出在其他方面?

那么,是否有一个执行问题?我做错了吗?很遗憾,我不能检查服务器的日志。我真的有点卡在这里了。

function performSignIn() {

  let headers = new Headers();

  headers.append('Content-Type', 'application/json');
  headers.append('Accept', 'application/json');

  headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
  headers.append('Access-Control-Allow-Credentials', 'true');

  headers.append('GET', 'POST', 'OPTIONS');

  headers.append('Authorization', 'Basic ' + base64.encode(username + ":" + password));

  fetch(sign_in, {
      //mode: 'no-cors',
      credentials: 'include',
      method: 'POST',
      headers: headers
    })
    .then(response => response.json())
    .then(json => console.log(json))
    .catch(error => console.log('Authorization failed : ' + error.message));
}

我使用的是Chrome浏览器。我也试过使用那个Chrome CORS插件,但我又收到了另一条错误信息。

响应中的'Access-Control-Allow-Origin'头的值 不能是通配符'*',当请求'的凭证模式是 'include'。因此,产地'http://127.0.0.1:3000'是不允许的 访问。的请求的凭证模式是由 XMLHttpRequest发起的请求的凭证模式是由withCredentials属性控制的。

解决办法

这个答案涵盖了很多内容,所以它分为三个部分。

  • 如何使用CORS代理来解决"无访问控制-允许-起源头 "问题
  • 如何避免CORS预检
  • 如何解决"Access-Control-Allow-Origin头不能是通配符 "的问题

    如何使用CORS代理来绕过"没有Access-Control-Allow-Origin头 "问题。 如果你不能控制你的前端JavaScript代码发送请求的服务器,而该服务器的响应问题仅仅是缺乏必要的 "访问控制-允许-起源 "头,你仍然可以通过CORS代理使请求工作。为了显示它是如何工作的,首先这里有一些不使用 CORS 代理的代码。

const url = "https://example.com"; // site that doesn’t send Access-Control-*
fetch(url)
.then(response => response.text())
.then(contents => console.log(contents))
.catch(() => console.log("Can’t access " + url + " response. Blocked by browser?"))

catch "块被击中的原因是,浏览器阻止该代码访问从https://example.com'返回的响应。浏览器这样做的原因是,该响应缺少Access-Control-Allow-Origin`响应头。 现在,这里是完全相同的例子,但只是加入了一个 CORS 代理。

const proxyurl = "https://cors-anywhere.herokuapp.com/";
const url = "https://example.com"; // site that doesn’t send Access-Control-*
fetch(proxyurl + url) // https://cors-anywhere.herokuapp.com/https://example.com
.then(response => response.text())
.then(contents => console.log(contents))
.catch(() => console.log("Can’t access " + url + " response. Blocked by browser?"))

***注意:如果在你尝试时https://cors-anywhere.herokuapp.com被关闭或不可用,那么请看下面如何在Heroku部署你自己的CORS Anywhere服务器,只需2-3分钟。 上面的第二个代码段可以成功地访问响应,因为将请求的URL改为https://cors-anywhere.herokuapp.com/https://example.com-by,只是在它前面加上代理的URL--导致请求通过该代理发出,然后。 1.将请求转发到https://example.com。 2.2. 接收来自https://example.com的响应。 3.在响应中添加 "Access-Control-Allow-Origin "头。 4.4. 将带有添加的头的响应传回给请求的前端代码。 然后,浏览器允许前端代码访问该响应,因为带有Access-Control-Allow-Origin响应头的响应是浏览器看到的。 你可以使用来自https://github.com/Rob--W/cors-anywhere/. 用一个小的curl脚本工作得很好--我得到了我的数据。 为了正确地使用curl进行测试,你需要模拟浏览器发送的preflightOPTIONS请求。

curl -i -X OPTIONS -H "Origin: http://127.0.0.1:3000" \
    -H 'Access-Control-Request-Method: POST' \
    -H 'Access-Control-Request-Headers: Content-Type, Authorization' \
    "https://the.sign_in.url"

...将https://the.sign_in.url替换成你实际的sign_inURL。 浏览器需要从该OPTIONS请求中看到的响应必须包括这样的头信息。

Access-Control-Allow-Origin:  http://127.0.0.1:3000
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type, Authorization

如果OPTIONS响应不包括这些头信息,那么浏览器就会在这里停止,甚至不会尝试发送POST请求。此外,响应的HTTP状态代码必须是2xx,通常是200或204。如果是其他的状态代码,浏览器就会在那里停止。 问题中的服务器对 "OPTIONS "请求的响应是501状态代码,这显然意味着它试图表明它没有实现对 "OPTIONS "请求的支持。在这种情况下,其他服务器通常以405 "方法不允许 "的状态代码来响应。 因此,如果服务器对 "OPTIONS "请求的响应是405或501,或者不是200或204,或者没有用这些必要的响应头来响应,你就永远无法从你的前端JavaScript代码中直接向该服务器发出 "POST "请求。 对于问题中的情况,避免触发预检的方法是。

  • 如果服务器不需要 "授权 "请求头,而是(例如)依赖嵌入在 "POST "请求正文中或作为查询参数的认证数据。
  • 如果服务器不要求POST主体有Content-Type: application/json媒体类型,而是接受POST主体为application/x-www-form-urlencoded,其参数名为json(或其他),其值为JSON数据

    如何解决"Access-Control-Allow-Origin头不能是通配符 "问题

    我得到了另一个错误信息。

    响应中的'Access-Control-Allow-Origin'头的值 当请求的凭证模式为时,必须不是通配符'&39;。 'include'。因此,产地'http://127.0.0.1:3000'是不允许的 访问。发起的请求的凭证模式是 XMLHttpRequest发起的请求由withCredentials属性控制。 对于包含凭证的请求,如果Access-Control-Allow-Origin响应头的值是*,浏览器不会让你的前端JavaScript代码访问响应。相反,这种情况下的值必须与你的前端代码的来源完全匹配,即http://127.0.0.1:3000。 见MDN HTTP访问控制(CORS)文章中的认证请求和通配符。 如果你控制了发送请求的服务器,那么处理这种情况的常用方法是配置服务器,使其获取Origin'请求头的值,并将其回传/反射到Access-Control-Allow-Origin'响应头的值。例如,使用nginx。

add_header Access-Control-Allow-Origin $http_origin

但这只是一个例子;其他(网络)服务器系统也提供了类似的方法来呼应起源值。

我使用的是Chrome浏览器。我也试过使用那个Chrome CORS插件 那个Chrome CORS插件显然只是头脑简单地注入了一个Access-Control-Allow-Origin:*"头到浏览器看到的响应中。如果该插件更聪明的话,它应该做的是将那个假的Access-Control-Allow-Origin响应头的值设置为你的前端JavaScript代码的实际来源,http://127.0.0.1:3000。 因此,避免使用该插件,即使是为了测试。它只是分散注意力。如果你想测试在没有浏览器过滤的情况下从服务器得到什么响应,你最好使用curl -H`,如上。

至于问题中的fetch(...)请求的前端JavaScript代码。

headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');

删除这些行。Access-Control-Allow-*头文件是响应头文件。你永远不会想在请求中发送它们。这样做的唯一效果是触发浏览器进行预检。

评论(8)

当客户端URL和服务器URL不匹配时,包括端口号,就会出现这种错误。在这种情况下,你需要启用你的服务的CORS,也就是跨源资源共享。

如果你正在托管一个Spring REST服务,那么你可以在博文Spring框架中的CORS支持中找到它。

如果你使用Node.js服务器托管一个服务,那么

  1. 停止Node.js服务器。

  2. npm install cors -save

  3. 在你的server.js中添加以下几行

    var cors = require('cors')

    app.use(cors())//在变量声明后使用这个

评论(4)

问题的出现是因为你在前端添加了以下代码作为请求头。

headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');

这些头信息属于response,而不是request。 所以要删除它们,包括那行:

headers.append('GET', 'POST', 'OPTIONS');

你的请求有'Content-Type: application/json',因此触发了所谓的CORS预飞。 这导致浏览器用OPTIONS方法发送请求。 详情请看[CORS preflight][1]。 <br/&gt。 因此在你的后端中,你必须通过返回响应头来处理这个preflighted请求,响应头包括 。

Access-Control-Allow-Origin : http://localhost:3000
Access-Control-Allow-Credentials : true
Access-Control-Allow-Methods : GET, POST, OPTIONS
Access-Control-Allow-Headers : Origin, Content-Type, Accept

当然,实际的语法取决于你的后端使用的编程语言。

在你的前端,应该是这样的。

function performSignIn() {
    let headers = new Headers();

    headers.append('Content-Type', 'application/json');
    headers.append('Accept', 'application/json');
    headers.append('Authorization', 'Basic ' + base64.encode(username + ":" +  password));
    headers.append('Origin','http://localhost:3000');

    fetch(sign_in, {
        mode: 'cors',
        credentials: 'include',
        method: 'POST',
        headers: headers
    })
    .then(response => response.json())
    .then(json => console.log(json))
    .catch(error => console.log('Authorization failed : ' + error.message));
}

[1]: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Preflighted_requests

评论(1)

在我的案例中,我使用了下面的解决方案

前端或Angular

post(
    this.serverUrl, dataObjToPost,
    {
      headers: new HttpHeaders({
           'Content-Type':  'application/json',
         })
    }
)

后端(我用php)

header("Access-Control-Allow-Origin: http://localhost:4200");
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header("Access-Control-Allow-Headers: Content-Type, Authorization");

$postdata = file_get_contents("php://input");
$request = json_decode($postdata);
print_r($request);
评论(0)

只是我的两点意见... 关于如何使用CORS代理来解决 "没有Access-Control-Allow-Origin头 "的问题

对于那些在后台使用php的用户来说,部署一个"CORS代理" 就这么简单:

  1. 创建一个名为'no-cors.php' 的文件,内容如下。

$URL = $_GET[&#39;url&#39;]; echo json_encode(file_get_contents($URL)); die();

  1. 在你的前端,做一些类似的事情。

`fetch('https://example.com/no-cors.php&#39;

  • '?url='
  • url) .then(response=>{/处理响应/})`。
评论(1)

删除这个。

credentials: 'include',
评论(0)

在我的案例中,web服务器阻止了"options&quot。 方法

检查你的网站服务器的选项方法

&gt.我在使用"webtier"。 我'正在使用"webtier&quot。

。 /www/webtier/domains/[domainname]/config/fmwconfig/components/OHS/VCWeb1/httpd.conf。


  RewriteEngine on
  RewriteCond %{REQUEST_METHOD} ^OPTIONS
  RewriteRule .* . [F]

改为


  RewriteEngine off
  RewriteCond %{REQUEST_METHOD} ^OPTIONS
  RewriteRule .* . [F]
评论(0)

我在我的本地得到这个错误。 我以管理员身份运行Visual Studio,它解决了。

评论(0)

使用dataType: &#39;jsonp&#39;对我来说是可行的。

   async function get_ajax_data(){
       var _reprojected_lat_lng = await $.ajax({
                                type: 'GET',
                                dataType: 'jsonp',
                                data: {},
                                url: _reprojection_url,
                                error: function (jqXHR, textStatus, errorThrown) {
                                    console.log(jqXHR)
                                },
                                success: function (data) {
                                    console.log(data);

                                    // note: data is already json type, you
                                    //       just specify dataType: jsonp
                                    return data;
                                }
                            });

 } // function               
评论(0)

我在使用Spring REST时,在WebMvcConfigurer中加入了AllowedMethods,解决了这个问题。

@Value( "${app.allow.origins}" )
    private String allowOrigins;    
@Bean
public WebMvcConfigurer corsConfigurer() {
            System.out.println("allow origin: "+allowOrigins);
            return new WebMvcConfigurerAdapter() {
                @Override
                public void addCorsMappings(CorsRegistry registry) {
                    registry.addMapping("/**")
                    //.allowedOrigins("http://localhost")
                    .allowedOrigins(allowOrigins)
                    .allowedMethods("PUT", "DELETE","GET", "POST");
                }
            };
        }
评论(0)

最快的修复方法是安装moesif CORS扩展。

https://chrome.google.com/webstore/detail/moesif-orign-cors-changer/digfbfaphojjndkpccljibejjbppifbc?hl=en-US

安装后,在浏览器中点击它来激活扩展。 确保图标的标签从 "关闭"![在此输入图片描述][1] 。 到 "on"[![在此输入图片描述][2]][2]。 然后刷新你的应用程序,你的API请求现在应该工作了! 这个插件肯定解决了这个问题。 但是,这个修复只适用于你自己的机器。 在本地开发中,安装一个插件,可以帮助你通过这个错误。

1:

[2]: https://i.stack.imgur.com/pip5A.png

评论(0)