Javascript 如何使用x-www-form-urlencoded强制Angular2发布

Javascript 如何使用x-www-form-urlencoded强制Angular2发布,javascript,angular,Javascript,Angular,我有一个项目需要使用Angular2(final)发布到一个旧的、遗留的Tomcat7服务器上,该服务器使用.jsp页面提供了一个有点REST风格的API 当该项目只是一个执行AJAX请求的简单JQuery应用程序时,这种方法工作得很好。然而,该项目的范围已经扩大,因此需要使用更现代的框架对其进行重写。Angular2看起来非常适合这项工作,但有一个例外:它拒绝使用任何选项执行POST请求,但将其作为表单数据,而API不会提取表单数据。API希望所有内容都是URL编码的,依靠Java的reque

我有一个项目需要使用Angular2(final)发布到一个旧的、遗留的Tomcat7服务器上,该服务器使用.jsp页面提供了一个有点REST风格的API

当该项目只是一个执行AJAX请求的简单JQuery应用程序时,这种方法工作得很好。然而,该项目的范围已经扩大,因此需要使用更现代的框架对其进行重写。Angular2看起来非常适合这项工作,但有一个例外:它拒绝使用任何选项执行POST请求,但将其作为表单数据,而API不会提取表单数据。API希望所有内容都是URL编码的,依靠Java的
request.getParameter(“param”)
语法来提取各个字段

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

从'@angular/core'导入{Injectable};
从'@angular/Http'导入{Headers,Response,Http,RequestOptions};
从“rxjs/Observable”导入{Observable};
导入'rxjs/add/operator/map';
@可注射()
导出类用户服务{
私有loggedIn=false;
私人罗吉努尔酒店http://localhost:8080/mpadmin/api/login.jsp';
私有头=新头({'Content-Type':'application/x-www-form-urlencoded'});
构造函数(私有http:http){}
登录(用户名、密码){
返回this.http.post(this.loginUrl,{'username':username,'password':password},this.headers)
.map((响应:响应)=>{
让user=response.json();
如果(用户){
localStorage.setItem('currentUser',JSON.stringify(user));
}
}
);
}
}
无论我将标题内容类型设置为什么,它总是以非编码表单数据的形式到达。这不是为了纪念我的头球

还有其他人遇到过这种情况吗?如何使用
request.getParameter(“param”)
强制Angular2以旧Java API可以读取的格式发布数据

编辑:对于将来发现这一点的任何人来说,解决方案其实非常简单。将帖子的主体设置为:

let body = `username=${username}&password=${password}`;`
let body = `username=${username}&password=${password}`;
this.http.post(this.loginUrl, body, { headers: headers }).map(...);

请参见下面的Brad示例。

2020年6月更新:此答案已存在4年,并且由于角度的API变化而不再有效。有关当前版本的方法,请参阅最新的答案。


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

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

this.http.post(this.loginUrl, body).map(...);
它当前不适用于您的原因是您没有以正确的格式编码正文数据,并且没有正确设置标题选项

您需要对身体进行如下编码:

let body = `username=${username}&password=${password}`;`
let body = `username=${username}&password=${password}`;
this.http.post(this.loginUrl, body, { headers: headers }).map(...);
您需要如下设置标题选项:

let body = `username=${username}&password=${password}`;`
let body = `username=${username}&password=${password}`;
this.http.post(this.loginUrl, body, { headers: headers }).map(...);
对于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 => {
        //...
    });
注3:使其按预期工作的事项:

  • 为您的身体使用URLSearchParams
  • 将正文转换为字符串
  • 设置标题的内容类型

  • 注意:较旧的浏览器确实需要polyfill!我使用了:
    npm I url search params polyfill--save
    然后添加到polyfills.ts:
    import'url search params polyfill'

    对于那些仍在寻找答案的人,我就是这样用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);
    

    不要设置内容类型标题,angular将为您解决此问题

    这就是Angular 7对我起作用的原因:

    const payload = new HttpParams()
      .set('username', username)
      .set('password', password);
    
    this.http.post(url, payload);
    
    无需使用此方法显式设置标头

    请注意,HttpParams对象是不可变的。所以,像这样做是行不通的,它会给你一个空的身体:

    const payload = new HttpParams();
    payload.set('username', username);
    payload.set('password', password);
    
    this.http.post(url, payload);
    

    我在这个问题上工作了几个小时后发现了这个解决方案

    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);
      }));
    

    }

    伙计们,我一直在研究这个问题,多亏了Josh Morony的这篇文章,我才知道问题出在哪里。基本上,当我开始测试我的api时,我使用的是POSTMAN,它工作得很好,但是当它用Ionic Angular实现它时,它就成了一个问题。本文中的解决方案只涉及导入
    body parser
    ,并将其用作服务器端根文件(索引)上的app.use(bodyParser.json())
    之类的应用程序中间件


    希望这会有所帮助,谢谢

    使用角度表单时,大多数参数将作为对象发送,因此您的登录函数很可能具有此对象
    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);
      }
    
    导出类身份验证服务{
    私有标头=新的HttpHeader(
    {
    “内容类型”:“应用程序/x-www-form-urlencoded”,
    接受:“*/*”,
    }
    );
    构造函数(私有http:HttpClient){}
    登录(数据):可观察{
    const body=新的HttpParams({fromObject:data});
    const options={headers:this.headers};
    返回此.http.post(`${environment.baseUrl}/token`,body.toString(),options);
    }
    
    8
    角度9

    这是一个有效的代码

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

    let params=新的HttpParams({
    fromObject:{email:usuario.email,密码:usuario.password,角色:usuario.role},
    });
    让httpOptions={
    标题:新的HttpHeaders({'Content Type':'application/x-www-form-urlencoded'}),
    };
    返回this.http.post(`${this.url}/usuario/signup`,params.toString(),httpOptions)(
    地图(
    (resp)=>{
    log('returnhttp',resp);
    返回响应;
    },
    (错误)=>{
    log('返回http错误',错误);
    返回误差;
    }
    )
    );
    尝试了URLSearchParams()选项,该选项不起作用,但您对正文的格式完全正确。这就成功了。标记为