我试图使用visualforce(VF)页面调用javascript。在VF页面中单击预览时,将执行方法。但是,当我试图看到Google Chrome中的响应“被CORS策略阻止时:请求的资源上没有'Access-Control-Allow-Origin'标头”错误。以下是VF的示例代码。
<apex:page controller="calljavascript_cls" >
<script>
function func()
{
var request = new XMLHttpRequest();
request.open('GET', 'https://copado.herokuapp.com/json/v1/webhook/metadata/AAAA?api_key=BBBB');
request.onreadystatechange = function () {
if (this.readyState === 4) {
console.log('Status:', this.status);
console.log('Headers:', this.getAllResponseHeaders());
console.log('Body:', this.responseText);
}
};
request.send();
}
</script>
<apex:outputText value="{!callfunc}" escape="false"></apex:outputText>
</apex:page>
Apex控制器类:
public class calljavascript_cls
{
public string callfunc{get;set;}
public calljavascript_cls()
{
callfunc='<script> func(); </script>';
}
}
我尝试了以下链接中给出的解决方案。不工作。
不知道该怎么办。请帮我。
您需要根据请求设置标题“Access-Control-Allow-Headers”,并且您的服务器还必须允许设置标题“Access-Control-Allow-Headers”,请调用CORS
request.setRequestHeader('Access-Control-Allow-Headers', '*');
我认为这会奏效。这个答案涵盖了很多方面,因此它分为三个部分:
如何使用CORS代理来解决“No Access-Control-Allow-Origin header”问题
如果您不控制服务器,您的前端JavaScript代码正在发送请求,而该服务器的响应问题只是缺少必要的Access-Control-Allow-Origin
标头,您仍然可以通过提出请求来完成工作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在您尝试时关闭或不可用,请参阅下文,了解如何在仅仅2-3分钟内在Heroku部署您自己的CORS Anywhere服务器。
上面的第二个代码片段可以成功访问响应,因为获取请求URL并将其更改为https://cors-anywhere.herokuapp.com/https://example.com - 只需在其前面添加代理URL - 导致请求通过该代理进行,然后:
https://example.com
。https://example.com
的回复。Access-Control-Allow-Origin
标头添加到响应中。然后,浏览器允许前端代码访问响应,因为具有Access-Control-Allow-Origin
响应头的响应是浏览器看到的。
您可以使用https://github.com/Rob--W/cors-anywhere/中的代码轻松运行自己的代理。 您还可以使用5个命令轻松地将自己的代理部署到Heroku,只需2-3分钟:
git clone https://github.com/Rob--W/cors-anywhere.git
cd cors-anywhere/
npm install
heroku create
git push heroku master
运行这些命令后,您最终将拥有自己运行的CORS Anywhere服务器,例如https://cryptic-headland-94862.herokuapp.com/。那么,不要在您的请求URL前加上https://cors-anywhere.herokuapp.com
前缀,而是使用您自己实例的URL作为前缀;例如,https://cryptic-headland-94862.herokuapp.com/https://example.com。
因此,如果你去尝试使用https://cors-anywhere.herokuapp.com,你会发现它已经失效(有时会是这样),然后考虑获得一个Heroku帐户(如果你还没有)并采取2或3分钟完成上述步骤,在Heroku上部署自己的CORS Anywhere服务器。
无论你是运行自己的还是使用https://cors-anywhere.herokuapp.com或其他开放代理,即使请求是触发浏览器执行CORS预检OPTIONS
请求的解决方案,这个解决方案也会起作用 - 因为在这种情况下,代理也会发送回Access-Control-Allow-Headers
和Access-Control-Allow-Methods
使预检成功所需的标题。
如何避免CORS预检
问题中的代码触发CORS预检 - 因为它发送了Authorization
标头。
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests
即使没有这个,Content-Type: application/json
标题也会触发预检。
什么“预检”意味着:在浏览器在问题的代码中尝试POST
之前,它将首先向服务器发送OPTIONS
请求 - 以确定服务器是否选择接收包含以下内容的跨源POST
Authorization
和Content-Type: application/json
标题。
它适用于小卷曲脚本 - 我得到了我的数据。
要使用curl
进行正确测试,您需要模拟浏览器发送的预检OPTIONS
请求:
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_in
URL。
浏览器需要从该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.如果是任何其他状态代码,浏览器将在那里停止。
问题中的服务器使用501状态代码响应OPTIONS
请求,这显然意味着它正在尝试表明它没有实现对OPTIONS
请求的支持。在这种情况下,其他服务器通常以405“方法不允许”状态代码进行响应。
因此,如果服务器使用405或501或者200或204之外的任何其他响应来回应POST
请求,那么您永远无法从前端JavaScript代码直接向该服务器发出OPTIONS
请求,或者它没有响应那些必要的响应标题。
避免在问题中触发案件预检的方法是:
Authorization
请求头,而是(例如)依赖于嵌入在POST
请求主体中的身份验证数据或作为查询参数POST
体具有Content-Type: application/json
媒体类型,而是接受POST
体作为application/x-www-form-urlencoded
,其参数名为json
(或其他),其值为JSON数据如何修复“Access-Control-Allow-Origin标头不能是通配符”问题
我收到另一条错误消息:
当请求的凭据模式为“include”时,响应中“Access-Control-Allow-Origin”标头的值不能是通配符“*”。因此,'http://127.0.0.1:3000'原产地不允许进入。 XMLHttpRequest发起的请求的凭据模式由withCredentials属性控制。
对于包含凭据的请求,如果Access-Control-Allow-Origin
响应头的值为*
,浏览器将不允许您的前端JavaScript代码访问响应。相反,在这种情况下,值必须与您的前端代码的起源http://127.0.0.1:3000
完全匹配。
请参阅MDN HTTP访问控制(CORS)文章中的Credentialed requests and wildcards。
如果您控制要发送请求的服务器,那么处理这种情况的常用方法是配置服务器以获取Origin
请求标头的值并将其回显/反映回Access-Control-Allow-Origin
响应标头的值。例如,使用nginx:
add_header Access-Control-Allow-Origin $http_origin
但这只是一个例子;其他(Web)服务器系统提供类似的方式来回显原始值。
我正在使用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-*
标头是响应标头。您永远不想在请求中发送它们。唯一的影响是触发浏览器进行预检。