从 angularjs 调用 REST 服务时本地主机上的 CORS 问题
CORS issue on localhost while calling REST service from angularjs
我正在学习 angularJS 并尝试在我的应用程序中实现它。
我有一个 RESTful WCF 服务托管在本地主机 IIS 上。
它定义了一个 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 中的响应:(对于我的 REST 服务),而来自 w3schools 的 REST 服务工作得很好。
{"data":null,"status":0,"config":{"method":"GET","transformRequest":[null],"transformResponse":[null],"url":"http://localhost:70/DocumentRESTService.svc/GetDocuments/","headers":{"Accept":"application/json,
text/plain, /"}},"statusText":""}
控制台显示以下错误消息。
- [Chrome Console:By 从 文件系统 ] 打开
XMLHttpRequest 无法加载 http://localhost:70/DocumentRESTService.svc/GetDocuments/。请求的资源上不存在 'Access-Control-Allow-Origin' header。因此不允许访问来源 'file://'。
- [Chrome Console:hosted 使用 方括号 ]
XMLHttpRequest 无法加载 http://localhost:70/DocumentRESTService.svc/GetDocuments/。请求的资源上不存在 'Access-Control-Allow-Origin' header。因此不允许访问来源'http://127.0.0.1:55969'。
- [Firefox 控制台:]
Cross-Origin 请求被阻止:同源策略不允许读取位于 http://localhost:70/DocumentRESTService.svc/GetDocuments/ 的远程资源。这可以通过将资源移动到同一域或启用 CORS 来解决。
这里的问题很少:
- 为什么 localhost 或我的 machineName 被认为是 cross-domain 请求?我在同一个域中,不是吗?
- 是否需要在我的服务端进行任何更改才能启用此行为?如果是,WCF 服务在哪里?(基于我阅读的内容 here)
- JSONP 在这种情况下有用吗?如果是,我将如何使用它?它是否适用于需要自定义 headers 的请求?(不确定它是什么,但在重新搜索时发现很多答案都提到了这一点。阅读链接会有所帮助。)
任何帮助或指导都会有所帮助。
P.S:
- IDE:Brackets ,如果重要的话 .
- AngularJS v1.4.3
- 我提到了各种涉及类似问题 (CORS) 的 Whosebug 问题,其中涉及 $resource 、 $provider 、 $config ,还有一些与删除一些 header 和添加一些值 header.我对此有点天真 - 任何对此的引用都会有所帮助。
我可以解决这个问题。
有几种方法可以做到这一点 - 我正在记下我尝试过的所有方法以及它们的参考资料。
回答
问题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?'
是的!服务器端本身需要更改。服务器应以
响应请求
Access-Control-Allow-Origin: *
header。这里的 * 可以替换为请求 header 本身或根据您的应用程序要求。优秀的博客 here 解释了使用 WCF REST 服务时的解决方法。您需要向每个服务方法添加以下行 (headers) 以在您的服务方法中启用 CORS。
WebOperationContext.Current.OutgoingResponse.Headers.Add(
"Access-Control-Allow-Origin", "*");
WebOperationContext.Current.OutgoingResponse.Headers.Add(
"Access-Control-Allow-Methods", "POST");
WebOperationContext.Current.OutgoingResponse.Headers.Add(
"Access-Control-Allow-Headers", "Content-Type, Accept");
规范here对于在服务器/客户端上启用 CORS 非常有帮助。
问题 3 的答案。
JSONP 主要适用于 GET 请求,不是最可取的用途,而是最推荐启用 CORS。 (我没有深入探索这个领域,但 Wiki & Whosebug article here 非常具有描述性)。
除此之外,出于测试目的,一个不错的 chrome extension here 可能会有所帮助。它可用于确保应用程序存在 CORS 问题。
我为模拟 Ionic 项目(运行 本地)与一些小型 Node.JS Web 服务(也 运行 本地)交互引起的 CORS 问题苦苦挣扎了太久.
看看简短的简单解决方法:Chrome 的插件 AllowControlAllowOrigin。
只需将单选按钮从红色切换为绿色,就不会再有被阻止的请求、错误或警告!
当然,这是一个临时解决方案,当停止本地测试的时间到来时,您可能不得不提出您的请求 headers。与此同时,这是避免浪费时间处理那些反复出现的烦人问题的好方法。
如果您在访问本地主机中的 REST API 运行 时遇到 AngularJS 应用程序中的 CORS 问题,请检查以下内容:在您的服务器应用程序中添加 CORS 过滤器。就我而言,我在 Spring application
中添加了以下代码
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 代码中,不要给 URL 像 http://localhost:8080/../。而不是 localhost 给出您的主机 IP 号。
它将正常工作
我正在学习 angularJS 并尝试在我的应用程序中实现它。
我有一个 RESTful WCF 服务托管在本地主机 IIS 上。 它定义了一个 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 中的响应:(对于我的 REST 服务),而来自 w3schools 的 REST 服务工作得很好。
{"data":null,"status":0,"config":{"method":"GET","transformRequest":[null],"transformResponse":[null],"url":"http://localhost:70/DocumentRESTService.svc/GetDocuments/","headers":{"Accept":"application/json, text/plain, /"}},"statusText":""}
控制台显示以下错误消息。
- [Chrome Console:By 从 文件系统 ] 打开
XMLHttpRequest 无法加载 http://localhost:70/DocumentRESTService.svc/GetDocuments/。请求的资源上不存在 'Access-Control-Allow-Origin' header。因此不允许访问来源 'file://'。
- [Chrome Console:hosted 使用 方括号 ]
XMLHttpRequest 无法加载 http://localhost:70/DocumentRESTService.svc/GetDocuments/。请求的资源上不存在 'Access-Control-Allow-Origin' header。因此不允许访问来源'http://127.0.0.1:55969'。
- [Firefox 控制台:]
Cross-Origin 请求被阻止:同源策略不允许读取位于 http://localhost:70/DocumentRESTService.svc/GetDocuments/ 的远程资源。这可以通过将资源移动到同一域或启用 CORS 来解决。
这里的问题很少:
- 为什么 localhost 或我的 machineName 被认为是 cross-domain 请求?我在同一个域中,不是吗?
- 是否需要在我的服务端进行任何更改才能启用此行为?如果是,WCF 服务在哪里?(基于我阅读的内容 here)
- JSONP 在这种情况下有用吗?如果是,我将如何使用它?它是否适用于需要自定义 headers 的请求?(不确定它是什么,但在重新搜索时发现很多答案都提到了这一点。阅读链接会有所帮助。)
任何帮助或指导都会有所帮助。
P.S:
- IDE:Brackets ,如果重要的话 .
- AngularJS v1.4.3
- 我提到了各种涉及类似问题 (CORS) 的 Whosebug 问题,其中涉及 $resource 、 $provider 、 $config ,还有一些与删除一些 header 和添加一些值 header.我对此有点天真 - 任何对此的引用都会有所帮助。
我可以解决这个问题。 有几种方法可以做到这一点 - 我正在记下我尝试过的所有方法以及它们的参考资料。
回答 问题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?'
是的!服务器端本身需要更改。服务器应以
响应请求Access-Control-Allow-Origin: *
header。这里的 * 可以替换为请求 header 本身或根据您的应用程序要求。优秀的博客 here 解释了使用 WCF REST 服务时的解决方法。您需要向每个服务方法添加以下行 (headers) 以在您的服务方法中启用 CORS。
WebOperationContext.Current.OutgoingResponse.Headers.Add(
"Access-Control-Allow-Origin", "*"); WebOperationContext.Current.OutgoingResponse.Headers.Add(
"Access-Control-Allow-Methods", "POST"); WebOperationContext.Current.OutgoingResponse.Headers.Add(
"Access-Control-Allow-Headers", "Content-Type, Accept");
规范here对于在服务器/客户端上启用 CORS 非常有帮助。
问题 3 的答案。
JSONP 主要适用于 GET 请求,不是最可取的用途,而是最推荐启用 CORS。 (我没有深入探索这个领域,但 Wiki & Whosebug article here 非常具有描述性)。
除此之外,出于测试目的,一个不错的 chrome extension here 可能会有所帮助。它可用于确保应用程序存在 CORS 问题。
我为模拟 Ionic 项目(运行 本地)与一些小型 Node.JS Web 服务(也 运行 本地)交互引起的 CORS 问题苦苦挣扎了太久.
看看简短的简单解决方法:Chrome 的插件 AllowControlAllowOrigin。
只需将单选按钮从红色切换为绿色,就不会再有被阻止的请求、错误或警告! 当然,这是一个临时解决方案,当停止本地测试的时间到来时,您可能不得不提出您的请求 headers。与此同时,这是避免浪费时间处理那些反复出现的烦人问题的好方法。
如果您在访问本地主机中的 REST API 运行 时遇到 AngularJS 应用程序中的 CORS 问题,请检查以下内容:在您的服务器应用程序中添加 CORS 过滤器。就我而言,我在 Spring application
中添加了以下代码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 代码中,不要给 URL 像 http://localhost:8080/../。而不是 localhost 给出您的主机 IP 号。
它将正常工作