AngularJS类型错误:无法读取未定义的“协议”属性

3

我已经在我的AngularJS应用程序中将$http > URL参数更改为

```javascript { withCredentials: true } ```

这是因为我需要从不同的域中获取数据。但是,现在我收到了一个错误消息:“无法使用凭据执行XMLHttpRequest:跨源请求时,只能使用凭据提供文件名和密码”。

有什么方法可以解决这个问题吗?

       $http({ method:'POST',
                   url:'http://localhost/api/clients.php'
       }).success(function(data,status,headers,config){
                     deferred.resolve(data);
       }).error(function(data,status,headers,config){ 
                     deferred.reject(status);
       });

to

       $http({ method:'POST',
                   url: ConfigService.Urls.Clients
       }).success(function(data,status,headers,config){
                     deferred.resolve(data);
       }).error(function(data,status,headers,config){ 
                     deferred.reject(status);
       });

以下是 ConfigService 的代码:

Urls: {},
loadUrls: function(){
   Urls.Clients = 'http://localhost/api/clients.php';
}

当然,在通过.Resolve加载控制器之前,我调用了loadUrls,因此我可以100%确定Urls.Clients不为null。
在我进行这个更改后,我开始收到错误:
TypeError: Cannot read property 'protocol' of undefined
    at urlIsSameOrigin (http://localhost/myapp/app/lib/angular/angular.js:13710:17)
    at $http (http://localhost/myapp/app/lib/angular/angular.js:7508:23)

令人困惑的是,除了我遇到的错误之外,该应用程序完全正常运行... 请问有人能告诉我在这里做错了什么,以及为什么会出现这个错误,如果该应用程序已经没有问题的话。


这个有用吗:https://dev59.com/6WEi5IYBdhLWcg3wX7TP - drew_w
@drew_w 不是的,因为这是一个不同的情况,在这里我不会分割头文件。 - MChan
你能把完整的$http调用放进去吗? - drew_w
基本上我在这里看到的唯一问题就是 Urls.Clients 必须以某种方式为 undefined。很抱歉不断地问问题,但是 loadUrls() 在哪里调用呢?我在你的代码中没有看到它。另外,如果您只是在服务中设置URLS而不是将其放入函数中,是否会更好? - drew_w
@drew_w ConfigService是一个服务,这就是加载URL的地方,然后我在需要的服务/控制器中注入这个服务。话虽如此,loadUrls会在第一个控制器(主页)加载时使用路由提供者解析。 - MChan
@drew_w 如果我直接在服务中设置URL,则不会显示错误,但是如果URL更改,则必须检查所有URL。 - MChan
2个回答

2
这明显是一个顺序问题。在第一次运行 $http 调用之前,loadUrls 并没有被调用。这可能是因为控制器不一定按照您期望的顺序加载 - 您不能指望路由提供程序在打开和启动主控制器之前运行其他控制器 - 这将取决于设置方式。鉴于您在此处提供的代码量很大,很难说到底出了什么问题。

考虑到这一点,您有几个通用选项可以解决这个问题:

  • Always call loadUrls() before you run a $http request. This isn't elegant but it will fix the issue
  • Wrap all of your $http calls and call loadUrls() in that wrapper. This is slightly better than the previous because if you need to change loadUrls() or make sure it is called only once you can implement that logic later.
  • You already observed this, but you can change your initialization to be directly in the service rather than in a routine provided by the service. This will fix the issue although it may leave you in a place where you have to update the service every time the url's change.
  • Live with the error, knowing that when the controller loads it will instantiate and get the correct data at that point in time. I don't often love solutions like this because it could cause errors later that are hard to trace but if you don't like any of the previous options this could technically be ok.
  • Use an app configuration, which is executed when the application loads (note that not all resources are initialized and injection is not allowed). An example from the documentation:

    angular.module('myModule', []).
      config(function(injectables) {
          // provider-injector
          // This is an example of config block.
          // You can have as many of these as you want.
          // You can only inject Providers (not instances)
          // into config blocks.
      }).
    

    You can use this or a run block to initialize what you want

我相信根据您的代码结构还有其他选项,但是希望这能帮助您入门。祝你好运!


你说得对,问题在于$http调用返回一个promise,但是导致错误的代码在promise被实现之前运行。有没有办法在应用程序启动时调用$http并防止promise失败时应用程序运行? - MChan
@MChan,我添加了另一个选项,可能会满足你的需求。因为Angular本身正在初始化,所以你无法做任何事情,但是runconfig可能会让你更进一步。 - drew_w
我无法在配置中注入我的服务,因此它不会有太大帮助。 - MChan
@MChan,你试过.run了吗? - drew_w
".run不会有任何区别,我的意思是即使承诺失败,它仍将继续运行run部分的代码,问题仍然存在。" - MChan
唯一的解决方法是在运行 $http 请求之前始终调用 loadUrls()...但这并不好,因为我将不得不在每个 $http 调用上至少复制相同的代码 20 次 :( - MChan

-2

我曾经遇到过同样的问题,我通过更改以下内容来解决它:

    var logoutURL = URL + '/logout';
    function sendLogoutHttp(){
        return $http({
            method: 'GET',
            url: logoutURL,
            headers: {'Content-Type': 'application/x-www-form-urlencoded'}
        });
    }

转换成这个

    function sendLogoutHttp(){
        var logoutURL = URL + '/logout';
        return $http({
            method: 'GET',
            url: logoutURL,
            headers: {'Content-Type': 'application/x-www-form-urlencoded'}
        });
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接