Angular2 Http 请求

9

你好,我正在尝试使用Angular2中的HTTP模块进行get请求。

Typescript(1.5)中编译一切顺利,但是Chrome在控制台中显示以下错误:

EXCEPTION: Error during instantiation of EntryList!. ORIGINAL
EXCEPTION: TypeError: Cannot read property 'merge' of undefined
ORIGINAL STACKTRACE: TypeError: Cannot read property 'merge' of undefined
at mergeOptions (angular2.dev.js:27991)  
at execute.Http.get (angular2.dev.js:28052)  
at EntryService.getEntries (services.js:17)
at new EntryList (entry-list.js:20)

Services.ts

/// <reference path="../typings/angular2/angular2.d.ts" />
import { Http, Observable } from "angular2/angular2"

export class EntryService {
    private _entries: Array<string>;
    private _http : Http;

    constructor() {     
        this._entries = ["test1", "test2", "test3"];
        this._http = new Http;      
    }

    get Entries() : Array<string> {
        return this._entries;
    }

    getEntries()
    {
        console.log(this._http);
        return this._http.get('http://localhost:53338/api/decisions')       
            .toRx()
            .map((response) => { 
                response.json()
            });     
    }
}

entry-list.ts

/// <reference path="../typings/angular2/angular2.d.ts" />
/// <reference path="../modules/services.ts" />

import { Component, View, NgFor } from "angular2/angular2"
import { EntryService } from "modules/services"

@Component({
    selector: 'entry-list'  
})
@View({
    directives: [ NgFor ],
    templateUrl: "../views/entry-list.html" 
})
export class EntryList {
    entries: Array<string>; 

    constructor(public service: EntryService) {     
        this.entries = this.service.Entries;
        this.service.getEntries().subscribe((response) => {     
            console.log(response);
        }); 
    }
}

app.ts

/// <reference path="typings/angular2/angular2.d.ts" />
/// <reference path="components/entry-list.ts" />
/// <reference path="modules/services.ts" />

import { Component, View, bootstrap, NgFor } from "angular2/angular2"
import { EntryList } from "components/entry-list"
import { EntryService } from "modules/services"

@Component({
    selector : "app",
    bindings: [ EntryService ]  
})
@View({
    directives: [ EntryList ],
    templateUrl: "views/app.html"   
})
class App { 
    constructor() {
        console.log('hit');
    }
}

bootstrap(App);

index.html

<html>
    <head>
        <title>SCM</title>
        <script src="https://github.jspm.io/jmcriffey/bower-traceur-runtime@0.0.88/traceur-runtime.js"></script>
        <script src="https://jspm.io/system@0.16.js"></script>      
        <script src="https://code.angularjs.org/2.0.0-alpha.34/angular2.dev.js"></script>
    </head>
    <body>
        <app></app>
        <script>System.import('app')</script>
    </body>
</html> 

我查看了 angular.io 网站上的 API 文档,但无法找到问题所在。

更新

Services.ts

/// <reference path="../typings/angular2/angular2.d.ts" />
import { Http, Observable, httpInjectables } from "angular2/angular2"

export class EntryService {
    private _entries: Array<string>;    

    constructor(private http: Http) {       
        this._entries = ["test1", "test2", "test3"];            
    }

    get Entries() : Array<string> {
        return this._entries;
    }

    getEntries()
    {
        console.log(this.http);
        return this.http.get('http://localhost:53338/api/decisions')        
            .toRx()
            .map((response) => { 
                response.json()
            });     
    }
}

entry-list.ts

/// <reference path="../typings/angular2/angular2.d.ts" />
/// <reference path="../modules/services.ts" />

import { Component, View, NgFor, Http, httpInjectables } from "angular2/angular2"
import { EntryService } from "modules/services"

@Component({
    selector: 'entry-list',
    bindings : [ Http, httpInjectables ]
})
@View({
    directives: [ NgFor ],
    templateUrl: "../views/entry-list.html" 
})
export class EntryList {
    entries: Array<string>; 

    constructor(public service: EntryService) {     
        this.entries = this.service.Entries;
        this.service.getEntries().subscribe((response) => {     
            console.log(response);
        }); 
    }
}

app.ts

/// <reference path="typings/angular2/angular2.d.ts" />
/// <reference path="components/entry-list.ts" />
/// <reference path="modules/services.ts" />

import { Component, View, bootstrap, NgFor, Http, httpInjectables } from "angular2/angular2"
import { EntryList } from "components/entry-list"
import { EntryService } from "modules/services"

@Component({
    selector : "app",
    bindings: [ EntryService, Http, httpInjectables ]   
})
@View({
    directives: [ EntryList ],
    templateUrl: "views/app.html"   
})
class App { 
    constructor() {
        console.log('hit');
    }
}

bootstrap(App);

不需要对index.html进行任何更改。

编辑:我的services.ts文件已更改以使其正常工作:

/// <reference path="../typings/angular2/angular2.d.ts" />
import { Injector, Http, httpInjectables } from "angular2/angular2"

export class EntryService {
    private _entries: Array<string>;    
    private http: Http;

    constructor() {     
        this._entries = ["test1", "test2", "test3"];        

        var injector = Injector.resolveAndCreate([
                httpInjectables,
                Http
            ]);
        this.http = injector.get(Http);                 
    }

    get Entries() : Array<string> {
        return this._entries;
    }

    getEntries()
    {       
        return this.http.get('http://localhost:53338/api/decisions')        
            .toRx()
            .map(response => response.json());      
    }
}
2个回答

10

不要自己实例化 Http,而是获取注入的实例:

public constructor(http : Http) {
    this.http = http;
}

文档中写道:

Http可以作为一个可注入的类使用,具有执行http请求的方法。

因此,我不确定如果您自己实例化它会得到什么结果,但由于一些未定义的内部问题,它无法执行get请求。

编辑:添加更多来源。

@Injectable()
export class Http {
    constructor(protected _backend: ConnectionBackend, protected _defaultOptions: RequestOptions) {}

    /**
     * Performs a request with `get` http method.
     */
    get(url: string, options?: RequestOptionsArgs): EventEmitter {
        return httpRequest(this._backend, new Request(mergeOptions(this._defaultOptions, options, RequestMethods.GET, url)));
  }
}

我在这里添加了Github存储库中Http类的一小部分。 你可以看到构造函数中给出了_backend和_defaultOptions,而你没有提供。方法get()将根据选项参数和构造函数中给出的_defaultOptions构建请求选项,因为你没有提供这些选项中的任何一个,我认为它会在mergeOptions调用中崩溃,你可以在这里找到:

function mergeOptions(defaultOpts, providedOpts, method, url): RequestOptions {
  var newOptions = defaultOpts;
  if (isPresent(providedOpts)) {
    // Hack so Dart can used named parameters
    newOptions = newOptions.merge(new RequestOptions({
      method: providedOpts.method,
      url: providedOpts.url,
      search: providedOpts.search,
      headers: providedOpts.headers,
      body: providedOpts.body,
      mode: providedOpts.mode,
      credentials: providedOpts.credentials,
      cache: providedOpts.cache
    }));
  }
  if (isPresent(method)) {
    return newOptions.merge(new RequestOptions({method: method, url: url}));
  } else {
    return newOptions.merge(new RequestOptions({url: url}));
  }
}

在函数的最后一个 if/else 块中。更多信息请查看源文件,位于这里


谢谢你的回答。我想尝试的第一件事是将Http类注入到我的EntryService类中。正如您从上面的代码中看到的,有3个单独的文件,我知道在Component注释中使用bindings属性将使该对象在整个应用程序中可用于注入,我已经尝试在那里指定Http类进行注入,但如果我尝试注入它,我会在EntryService构造函数上出现错误。您知道如何使Http对象可以注入到EntryService中吗? - Werner Swart
实际上,我只是改了代码。而且没有错误,无论是 TypeScript 编译器还是 Chrome 内部都没有错误,但应用程序却无法正常工作。 - Werner Swart
我已经更新了代码,也尝试将Http对象传递到引导调用中,但没有成功(虽然上面的代码中没有)。 - Werner Swart
只需在引导程序中提供httpInjectables,并仅在服务中包含Http。然后,您就不需要再将其绑定到应用注入器上了。否则,您可以尝试设置一个plnkr并重现该问题吗? - Arnaud Boeglin
抱歉回复晚了,我花了一些时间阅读Http.ts文件和其他资源,以便更好地理解您的答案。我仍然不知道如何向子组件的子类注入变量,但我在我的services.ts文件中设法实例化一个注射器,然后执行var http = injector.get(Http) ,它起作用了。代码如下: var injector = Injector.resolveAndCreate([ httpInjectables, Http ]); this.http = injector.get(Http); 感谢您的帮助!! - Werner Swart
显示剩余2条评论

2

你真的想为了CRUD / HTTP请求而使用另一个库吗?

我强烈建议使用 ES6 中默认的 fetch。我认为它不仅比 angular2/http 更简单,而且在当前和未来版本中也是标准。

** 它可以直接在 Safari、Chrome、IE-Edge 和 Firefox 上运行。


3
需要翻译的内容:An example would be helpful to support your case。一个例子会有助于支持你的论点。 - Serj Sagan

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