如何使用x-www-form-urlencoded强制Angular2进行POST

Dam*_*ell 64 javascript angular

我有一个项目需要使用Angular2(final)发布到旧的,遗留的Tomcat 7服务器,使用.jsp页面提供一些REST-ish API.

当项目只是一个执行AJAX请求的简单JQuery应用程序时,这很好用.但是,项目的范围已经扩大,需要使用更现代的框架进行重写.Angular2对于这项工作看起来很棒,但有一个例外:它拒绝使用任何选项执行POST请求,但拒绝执行API不提取的表单数据.API期望所有内容都是urlencoded,依靠Java的request.getParameter("param")语法来提取单个字段.

这是从我的user.service.ts剪下来的:

import { Injectable }    from '@angular/core';
import { Headers, Response, Http, RequestOptions } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';

@Injectable()
export class UserService {
    private loggedIn = false;
    private loginUrl = 'http://localhost:8080/mpadmin/api/login.jsp';
    private headers = new Headers({'Content-Type': 'application/x-www-form-urlencoded'});

    constructor(private http: Http) {}

    login(username, password) {
        return this.http.post(this.loginUrl, {'username': username, 'password':  password}, this.headers)
            .map((response: Response) => {
                let user = response.json();
                if (user) {
                    localStorage.setItem('currentUser', JSON.stringify(user));
                }
            }
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

无论我将头部内容类型设置为什么,它总是以非编码形式数据的形式到达.它没有尊重我正在设置的标题.

有人遇到过这种情况么?你如何强制Angular2以一种旧的Java API可以读取的格式POST数据request.getParameter("param")

编辑:对于将来发现这一点的其他人来说,解决方案实际上非常简单.像这样设置帖子的主体:

let body = `username=${username}&password=${password}`;`
Run Code Online (Sandbox Code Playgroud)

请参阅下面的Brad示例.

Bra*_*rad 87

您可以使用URLSearchParams请求的主体,而角度将自动设置内容类型application/x-www-form-urlencoded并正确编码正文.

let body = new URLSearchParams();
body.set('username', username);
body.set('password', password);

this.http.post(this.loginUrl, body).map(...);
Run Code Online (Sandbox Code Playgroud)

它目前不适合您的原因是您没有以正确的格式对正文数据进行编码,而且您没有正确设置标题选项.

你需要像这样对身体进行编码:

let body = `username=${username}&password=${password}`;
Run Code Online (Sandbox Code Playgroud)

您需要设置标题选项,如下所示:

this.http.post(this.loginUrl, body, { headers: headers }).map(...);
Run Code Online (Sandbox Code Playgroud)

  • @DamonKaswell使用URLSearchParams作为正文也没有成功,对我来说也是如此.如果我这样做,内容类型是application/json,发布的json数据是一个空对象.我在Angular 4.0上.我最终做了这个`const headers = new Headers({'Content-Type':'application/x-www-form-urlencoded'}); const options = new RequestOptions({headers:headers}); const body:URLSearchParams = new URLSearchParams(); body.set('username',username); body.set('密码',密码); 返回this.http.post(API_URL +'login',body.toString(),options)` (7认同)
  • 尝试了URLSearchParams()选项,该选项不起作用,但您对主体的格式完全正确.这就是诀窍.标记为答案,我将更新帖子供其他人查找. (3认同)

Mic*_*ick 82

对于Angular 4.3 +/5 +(新的HTTPClient),请使用以下命令:

let body = new URLSearchParams();
body.set('user', username);
body.set('password', password);

let options = {
    headers: new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded')
};

this.http
    .post('//yourUrl.com/login', body.toString(), options)
    .subscribe(response => {
        //...
    });
Run Code Online (Sandbox Code Playgroud)

注意3使它按预期工作的事情:

  1. 使用URLSearchParams为您的身体
  2. 将body转换为字符串
  3. 设置标题的内容类型

注意:较旧的浏览器确实需要填充!我用过:npm i url-search-params-polyfill --save然后添加到polyfills.ts:import 'url-search-params-polyfill';

  • 不应该使用"new"Angular 5`HttpParams`而不是"old"`URLSearchParams`? (5认同)
  • HttpParams工作并避免polyfill,但它是不可变的,所以你必须使用body = body.set('user',username); 等等 (2认同)

Joh*_*int 32

对于那些仍在寻找答案的人来说,这就是我用Angular 5和HttpClient解决它的方法:

const formData = new FormData();

// append your data
formData.append('myKey1', 'some value 1');
formData.append('myKey1', 'some value 2');
formData.append('myKey3', true);

this.httpClient.post('apiPath', formData);
Run Code Online (Sandbox Code Playgroud)

千万不要设置Content-Type头,角将解决您的问题!

  • 该请求将生成标头“multipart/form-data”,如果服务器仅接受“x-www-form-urlencoded”,则该请求将不起作用, (3认同)
  • 这对我不起作用。它最终以Content-Type的形式发送数据:multipart / form-data (2认同)

Rob*_*ner 18

这就是我在Angular 7中工作的原因:

const payload = new HttpParams()
  .set('username', username)
  .set('password', password);

this.http.post(url, payload);
Run Code Online (Sandbox Code Playgroud)

无需使用此方法显式设置标头。

请注意,HttpParams对象是不可变的。因此,执行以下操作将无法正常工作,它会给您带来空洞的身体:

const payload = new HttpParams();
payload.set('username', username);
payload.set('password', password);

this.http.post(url, payload);
Run Code Online (Sandbox Code Playgroud)

  • 我在这里遗漏了一些东西,但这不会对参数进行编码吗? (2认同)

小智 6

角9

这是一个有效的代码。

选择适合您的其他选项,以返回不成功的答案。

 let params = new HttpParams({
      fromObject: { email: usuario.email, password: usuario.password, role: usuario.role },
    });

    let httpOptions = {
      headers: new HttpHeaders({ 'Content-Type': 'application/x-www-form-urlencoded' }),
    };
    
    return this.http.post(`${this.url}/usuario/signup`, params.toString(), httpOptions).pipe(
      map(
        (resp) => {
        
          console.log('return http', resp);
          return resp;
        },
        (error) => {
          console.log('return http error', error);
          return error;
        }
      )
    );
Run Code Online (Sandbox Code Playgroud)

记住你使用的字符串fromString而不是fromObject


小智 5

我在解决这个问题几个小时后找到了这个解决方案

login(userName: string, password: string) {
const headers = new Headers();
headers.append('Accept', 'application/json');
headers.append('Content-Type', 'application/x-www-form-urlencoded');
headers.append( 'No-Auth', 'True');

const body = new URLSearchParams();
body.set('username', userName);
body.set('password', password);
body.set('grant_type', 'password');

return this.http.post(
    this.baseUrl + '/token'
   , body.toString()
   , { headers: headers }
  )
  .pipe(map(res => res.json()))
  .pipe(map(res => {
    localStorage.setItem('auth_token', res.auth_token);
    return true;
  }))
  .pipe(catchError((error: any) => {
    return Observable.throw(error);
  }));
Run Code Online (Sandbox Code Playgroud)

}


小智 5

当使用角度形式时,大多数参数将作为对象发送,因此您的登录函数很可能会将此对象 form.value = {username: 'someone', password:'1234', grant_type: 'password'}作为参数

将此对象作为x-www-form-urlencoded发送,您的代码将是

export class AuthService {
    private headers = new HttpHeaders(
        {
            'Content-Type':  'application/x-www-form-urlencoded',
            Accept: '*/*',
        }
    );
  constructor(private http: HttpClient) { }

  login(data): Observable<any> {
    const body = new HttpParams({fromObject: data});
    const options = { headers: this.headers};
    return this.http.post(`${environment.baseUrl}/token`, body.toString(), options);
  }
Run Code Online (Sandbox Code Playgroud)


Kin*_*une 5

对于 Angular 12,这对我有用。


  options = {
    headers: new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded')
  };

  params = new HttpParams()
  .set("client_id", "client_id")
  .set("client_secret", "client_secret")
  .set("grant_type", "grant_type")
  .set("scope", "scope")

  getToken(){
    return this._http.post(`${URL}`, this.params, this.options)
  }

Run Code Online (Sandbox Code Playgroud)

另外,请记住在顶部导入以下内容import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';

另请注意,与其他方法不同,我们不使用 toString(),因为它是多余的。