从 angularjs 调用 REST 服务时本地主机上的 CORS 问题
Posted
技术标签:
【中文标题】从 angularjs 调用 REST 服务时本地主机上的 CORS 问题【英文标题】:CORS issue on localhost while calling REST service from angularjs 【发布时间】:2015-10-15 06:25:56 【问题描述】:我正在学习 angularJS 并尝试在我的应用程序中实现它。
我在 localhost IIS 上托管了一个 RESTful WCF 服务。 它定义了一个 GET 方法来获取文档列表:http://localhost:70/DocumentRESTService.svc/GetDocuments/
现在我正在尝试在我的 Angular 应用程序中使用此服务并显示数据。 以下是代码: html:
<html>
<script src="../../dist/js/angular/angular.min.js"></script>
<script src="../../assets/js/one.js"></script>
<body ng-app="myoneapp" ng-controller="oneAppCtrl">
"Hello" + "AngularJS"
<hr>
<h1> Response from my REST Service </h1>
hashValue
<hr>
<h1> Response from w3school REST Service </h1>
names
</body>
</html>
JS:
angular.module('myoneapp', [])
.controller('oneAppCtrl', function($scope,$http)
$scope.documentValue = ;
$http(method: 'GET',
url: 'http://localhost:70/DocumentRESTService.svc/GetDocuments/',
headers:
// 'Access-Control-Allow-Origin': 'http://localhost'
)
.success(function(data) alert('Success!'); $scope.documentValue=data;)
.error(function(data) alert('Error!'); $scope.documentValue=data; alert('Error!' + $scope.documentValue);)
.catch(function(data) alert('Catch!'); $scope.documentValue= data;);
$http.get("http://www.w3schools.com/angular/customers.php")
.success(function(response) $scope.names = response.records;);
);
奇怪的行为是这段代码在 IE11 中运行良好,而在 Chrome/Firefox 中无法运行。
以下是 chrome:(for my REST service) 中的响应,而 w3schools 的 REST 服务运行良好。
"data":null,"status":0,"config":"method":"GET","transformRequest":[null],"transformResponse":[null],"url":" http://localhost:70/DocumentRESTService.svc/GetDocuments/","headers":"Accept":"application/json, 文本/纯文本,/","statusText":""
控制台显示以下错误消息。
[Chrome 控制台:通过从文件系统打开]XMLHttpRequest 无法加载 http://localhost:70/DocumentRESTService.svc/GetDocuments/。请求的资源上不存在“Access-Control-Allow-Origin”标头。因此,Origin 'file://' 不允许访问。
[Chrome 控制台:使用方括号托管]XMLHttpRequest 无法加载 http://localhost:70/DocumentRESTService.svc/GetDocuments/。请求的资源上不存在“Access-Control-Allow-Origin”标头。因此不允许访问 Origin 'http://127.0.0.1:55969'。
[Firefox 控制台:]跨域请求被阻止:同源策略不允许读取位于http://localhost:70/DocumentRESTService.svc/GetDocuments/ 的远程资源。这可以通过将资源移动到同一域或启用 CORS 来解决。
这里的问题很少:
-
为什么 localhost 或 my machineName 被认为是跨域请求?我在同一个域中,不是吗?
是否需要在我的服务端进行任何更改才能启用此行为?如果是,WCF 服务在哪里?(基于我阅读的内容here)
JSONP 在这种情况下有用吗?如果是,我将如何使用它?它是否适用于需要自定义标头的请求?(不太确定它是什么,但在重新搜索时发现很多答案都提到了这一点。阅读链接会有所帮助。)
任何帮助或指导都会有所帮助。
PS:
IDE:Brackets,如果这很重要的话。 AngularJS v1.4.3 我已经提到了各种 *** 问题,这些问题涉及到类似的问题 (CORS),其中涉及 $resource 、 $provider 、 $config ,还有一些与删除某些标头并在标头中添加一些值有关。我对此有点天真 - 任何对此的引用都会有所帮助。【问题讨论】:
不同的端口或子域也被浏览器考虑跨域。大概您的页面正在不同的端口上打开?如何为任何服务器环境实施 CORS 到处都有很好的记录……简单的网络搜索。打开页面时也不能使用file://
协议。甚至 CORS 也无济于事
您也通过 localhost url 加载页面? (相对于 file:// 或 127.0.0.1)
出于兴趣,IE 并不关心 CORS 的端口号——因此您可以使用它进行测试。或者,使用 chrome --args --disable-web-security
启动 chrome,它不会对 CORS 进行检查。
@TZHX 问题是忘记它已被禁用并在您的机器上留下安全漏洞。启用 CORS 是最理想的 IMO
@charlietfl 完全同意,从长远来看——但要开始做一些事情,了解解决方法会很有用。
【参考方案1】:
我可以解决这个问题。 有几种方法可以做到这一点 - 我正在记下我尝试过的所有内容及其参考。
回答 问题1。
'Why is localhost or my machineName considered to be a cross-domain request?'
正如@charlietfl 提到的,我研究了here:不同的端口或子域也被浏览器考虑跨域。
回答 问题2。
'Are there any changes required to do at my service end to enable this behavior?'
是的!服务器端本身需要更改。服务器应该用
响应请求访问控制允许来源:*
标题。这里 * 可以替换为请求标头本身或根据您的应用程序要求。优秀的博客here 解释了如果您使用 WCF REST 服务的解决方法。您需要在每个服务方法中添加以下行(标题)以在您的服务方法中启用 CORS。
WebOperationContext.Current.OutgoingResponse.Headers.Add( “访问控制允许来源”,“*”); WebOperationContext.Current.OutgoingResponse.Headers.Add( “访问控制允许方法”,“POST”); WebOperationContext.Current.OutgoingResponse.Headers.Add( "Access-Control-Allow-Headers", "Content-Type, Accept");
规范here 非常有助于在服务器/客户端上启用 CORS。
回答问题3。
JSONP 主要适用于 GET 请求并且不是最可取的使用,而是最推荐启用 CORS。 (我没有深入探索这个领域,但 Wiki 和 *** 文章 here 非常具有描述性)。
除此之外,为了测试目的,一个漂亮的 chrome extension here 可能会有所帮助。它可用于确保应用程序存在 CORS 问题。
【讨论】:
所以这是对问题的回答,还是试图回答 cmets? @Claies :大多数情况下这可以被视为一个答案,但如果有人提出纠正/补充这种理解,请等待其他人回应。【参考方案2】:由于模拟 Ionic 项目(在本地运行)与一些小型 Node.JS Web 服务(也在本地运行)的交互导致的 CORS 问题,我苦苦挣扎了太久。
看看简单的解决方法:Chrome 的插件 AllowControlAllowOrigin。
https://chrome.google.com/webstore/search/cross%20origin?utm_source=chrome-ntp-icon&_category=extensions
只需将单选按钮从红色切换到绿色,就不会再被阻止请求、错误或警告! 当然,这是一个临时解决方案,当停止本地测试的时间到来时,您可能不得不把手放在请求标头中。同时,这是避免在那些烦人的反复出现的问题上浪费时间的好方法。
【讨论】:
这是迄今为止我遇到的最简单的解决方案。特别是在处理您无权访问的远程服务器时。【参考方案3】:如果您在访问 localhost 机器中运行的 REST API 时遇到 AngularJS 应用程序中的 CORS 问题,请检查以下内容:在您的服务器应用程序中添加 CORS 过滤器。就我而言,我在 Spring 应用程序中添加了以下代码
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component
public class SimpleCORSFilter implements Filter
private final Logger log = LoggerFactory.getLogger(SimpleCORSFilter.class);
public SimpleCORSFilter()
log.info("SimpleCORSFilter init");
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With, remember-me");
chain.doFilter(req, res);
@Override
public void init(FilterConfig filterConfig)
@Override
public void destroy()
在 angularjs 代码中,不要给出 http://localhost:8080/../ 之类的 URL。而不是 localhost 提供您的主机 IP 号。
它会正常工作
【讨论】:
我只是遇到了 express 和 angular2 的问题,我不必设置 Access-Control-* 标头,我只是将 angular 更改为指向 127.0.0.1:3000 并清除了问题了。谢谢!以上是关于从 angularjs 调用 REST 服务时本地主机上的 CORS 问题的主要内容,如果未能解决你的问题,请参考以下文章
AngularJS 中跨域 REST 调用的正确架构模式是啥?
为啥 AngularJS 应用程序不能在不同的服务器上使用 REST 服务?
如何使用 REST 将数据从 AngularJS 发布到 Struts 2
使用 ANGULARJS 从 Jersey rest api 调用中下载/保存文件。文件附加响应为“Content-Disposition”