使用 HttpClient 和 RXJS 将数据发布到 Web API withCredentials: true

Posted

技术标签:

【中文标题】使用 HttpClient 和 RXJS 将数据发布到 Web API withCredentials: true【英文标题】:Using HttpClient and RXJS to POST data to 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 参数下看到一条红线我这样做时的服务。

【问题讨论】:

【参考方案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 之前一样。我在示例中的操作方式有效,但您的示例无效。 :/ 我查看了其他答案,它们与您的示例类似:***.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 变量中,然后将其附加到我的授权标头。

以上是关于使用 HttpClient 和 RXJS 将数据发布到 Web API withCredentials: true的主要内容,如果未能解决你的问题,请参考以下文章

如何使用rxjs map挖掘HttpClient get请求响应?

将订阅响应作为参数发送到方法 Angular/rxJs

RxJs映射后的未定义值

Angular 6 和 RxJS 6 重大变化

rxjs http请求未缓存

Angular7 HttpClient处理多个请求