【问题标题】:Using HttpClient and RXJS to POST data to Web API withCredentials: true使用 HttpClient 和 RXJS 将数据发布到 Web API withCredentials: true
【发布时间】:2018-07-24 21:58:35
【问题描述】:

我有一个Angular 服务已连接到我的.NET Web API,我正在尝试将POST 一些数据发送到API。目前我使用的是HTTP 而不是HttpClient,而且我没有发送任何数据。但服务已成功连接到 API。

在将实际数据从我的 Angular 控制器传递到服务(进而传递到 API)以及在服务中实现 HttpClient 方面需要帮助。到目前为止,我的控制器只是调用了我的服务的 myFunction() 函数,并且没有传递任何参数,因此没有数据。我不确定在服务的 RXJS 部分的哪个位置附加我的数据。

注意:但是我实现了这个,由于我的 API 的配置,我仍然需要它通过withCredentials: true

Web API 控制器:

namespace api.controllers
{
    [Authorize]
    public class ValuesController : ApiController
     {
        static List<string> strings = new List<string>()
        {
            "value0", "value1", "value2"
        };

        // GET api/values
        public IEnumerable<string> Get()
        {
            return strings;
        }

        // GET api/values/5
        public string Get(int id)
        {
            return "value";
        }

        // POST api/values
        public void Post([FromBody]string value)
        {
            strings.Add(value);
        }

        // PUT api/values/5
        public void Put(int id, [FromBody]string value)
        {
        }

        // DELETE api/values/5
        public void Delete(int id)
        {
        }

    }
}

Web API web.config 文件(CORS 设置):

<httpProtocol>
  <customHeaders>
    <add name="Access-Control-Allow-Origin" value="http://localhost:5200" />
    <add name="Access-Control-Allow-Headers" value="*" />
    <add name="Access-Control-Allow-Methods" value="GET,POST,PUT,DELETE,OPTIONS" />
    <add name="Access-Control-Allow-Credentials" value="true" />
  </customHeaders>
</httpProtocol>


myComponent.component.ts:

  myService: MyService;

  constructor(myService: MyService) {
      this.myService = myService;
      this.myService.myFunction();
   }


myService.service.ts:

import { Injectable } from '@angular/core';
import { Http, Response, Request, Headers } from '@angular/http';
// import { HttpClient, HttpResponse, HttpRequest, HttpHeaders, HttpInterceptor, HttpHandler, HttpEvent } from '@angular/common/http';

import { Observable } from 'rxjs';
import { from } from 'rxjs';
import { map, filter, catchError, mergeMap } from 'rxjs/operators';

@Injectable({
  providedIn: 'root'
})

export class MyService {
  http: Http;

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

  public myFunction() {
    let request = new Request({
      method: "POST",
      url: "http://localhost:9090/api/values",
      withCredentials: true
    });

    return this.http.request(request)
      .pipe(map(res => res.json()))
      .subscribe(
        data => console.warn(data),
        err => console.error(err),
        () => console.log("empty")
      );
  }
}


如何从我的控制器将一些实际数据附加到此服务?我该如何调整服务以使用 HttpClient 呢?我尝试将所有http: Http 引用更改为HttpClient,完成所有HttpClient 导入并注释掉.map/json portions,但我仍然在return this.http.request(request) 行中的request 参数下看到一条红线我这样做时的服务。

【问题讨论】:

    标签: angular http asp.net-web-api rxjs httpclient


    【解决方案1】:

    我使用这个概念,希望它也适用于你。

    为您的数据创建属性类(将其与您的 .net API 上的类匹配),这也提供了简单的数据处理 型号

    export class MyData
    {
     username:string;
     password:string;
     isAuthenticated:boolean;
    }
    

    服务

    import { Http, Response, Request, Headers } from '@angular/http';
    
    export class MyService {     
    
      constructor(private http: Http) {}
    
    public myFunction(body:MyData) {
     let url = 'http://localhost:9090/api/values'
        return this.http.post(url,body)
          .pipe(map(res => res.json()))          
      }
    }
    

    TS

    returnValue:any;
    myData:MyData;
    constructor(private service:MyService){
    this.myData = new MyData();
    }
    myFunction()
    {
     this.myData.username = 'anything';
     this.myData.password = 'mypw';
     this.myData.isAuthenticated = true;
    
     this.returnValue = this.service.myFunction(this.myData)
     .subscribe(res=>{console.log(res)})
    }
    

    .NET API

    [HttpPost]
    public void MYAPI([FromBody]MyData model)
    {
    
        string uname = model.username;
        string pw = model.password;
    }
    

    【讨论】:

    • 谢谢!您会注意到,在我的示例中,我将withCredentials: true 键/值对传递给了服务中的myFunction。由于我的 API 配置,这是我必须具备的。如何在您的示例中包含 withCredentials: true
    • 嗨,Kyle,您能否解决问题(发帖时传递凭据?)
    【解决方案2】:

    为了使用 HttpClient,您必须在 app.module.ts 中导入 HttpClientModule HttpModule 并开始注入 HttpClient http 中的对象

    @Injectable({
      providedIn: 'root'
    })
    
    export class MyService {
    
      constructor(private http: HttpClient) {
      };
    
      public myFunction(body) {
        let requestOptions = { withCredentials : true };
        return this.http.post("http://localhost:9090/api/values",body,requestOptions);
      }
    }
    

    当你使用 HttpClient 时你不需要做.map(res =&gt; res.json())

    组件

     constructor(myService: MyService) {
          this.myService = myService;
          this.myService.myFunction({username:'test',password:'123465'})
          .subscribe(data => console.warn(data), err => console.error(err),() => console.log("empty")
          );
       }
    

    通常您不需要订阅您的服务,因此您可以获得 数据到组件

    ngOnInit

    作为一般的良好做法,您必须在 ngOninit 方法

    complete guide about http , RequestOptions

    最后这是打字稿提示

    这是简写语法

     constructor(private http: HttpClient) {
      };
    

    到这里

    private http: HttpClient;
     constructor(http: HttpClient) {
       this.http = http
      };
    

    【讨论】:

    • 如果你写constructor(private myService: MyService) {...}这个组件会比你可以在everythere使用this.myService更干净。
    • 我在最后写了一个提示,这样他就不会感到困惑@DanielHabenicht
    • 非常感谢!在我让它工作之前还有一个问题。您会注意到,在我的示例中,我将withCredentials: true 键/值对传递给了服务中的myFunction。由于我的 API 配置,这是我不能没有的。如何在您的示例中包含 withCredentials: true
    • @KyleVassella 我已经更新了我的答案,并告诉你如何设置请求选项
    • 再次感谢。我是如此接近。但是使用你的例子,我现在得到一个401 (Unauthorized) 错误,和一个Response for preflight has invalid HTTP status code 401,就像我在实现我原来的withCredentials: true 之前一样。我在示例中的操作方式有效,但您的示例无效。 :/ 我查看了其他答案,它们与您的示例类似:stackoverflow.com/questions/50606752/… 有什么想法吗?
    【解决方案3】:

    除了服务之外,您的代码看起来还不错。 我还看到你的 API 有 [Authorize]。你需要通过授权

    例如:

    const httpOptions = {
     headers: new HttpHeaders({
      'Authorization': myToken
     }),
     withCredentials: true
    };
    

    在您的 Http 请求上,这样您就不会收到需要授权的错误。

    此参考可能有用:https://angular.io/guide/security

    使用 HttpClient 的服务:

     import { Injectable } from '@angular/core';
     import { HttpClient, HttpHeaders } from '@angular/common/http';
     import { Observable } from 'rxjs';
    
     // api path
     const API_URL = 'http://10.111.1.23:80/api/my_api/api/yourController';
    
     // add http headers.
     const httpOptions = {
        headers: new HttpHeaders({
        'Content-Type': 'application/json'
       })
      };
    
     @Injectable()
     export class MyService {
    
     // inject the Http Client to the constructor
     constructor(private _http: HttpClient) { };
    
     myFunction(entity: any): Observable<yourModel> {
        // using http client the return value of you api is
        // directly map to your model
        return this._http.post<yourModel>(API_URL ,
          entity, httpOptions);
     );
    }
    

    【讨论】:

    • Authorization 部分是我卡住的地方。无论我尝试什么,当POSTing 数据时,我仍然会收到OPTIONS 401 (unauthorized) 错误。我已启用 cors 等。**我的 Web API 目前正在使用 Windows Authentication。我相信这可能是 [Authorize] 属性相关的内容。我什至可以将什么作为'Authorization': mytoken 的值传递?什么会代替mytoken?谢谢你的回答。
    • myToken 是一个包含 jwt 令牌的变量(请参阅 jwt.io),在我的情况下,我将令牌存储在 localStorage 中,然后检索它并将其存储到 myToken 变量中,然后将其附加到我的授权标头。
    猜你喜欢
    • 1970-01-01
    • 2018-08-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-10
    • 2015-11-17
    相关资源
    最近更新 更多