我有一个项目需要使用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));
}
}
);
}
}
无论我将头部内容类型设置为什么,它总是以非编码形式数据的形式到达。它没有尊重我设置的标题。
还有其他人遇到过这个吗?你如何强制Angular2以一种可以由旧的Java API使用request.getParameter("param")
读取的格式POST数据?
编辑:对于将来发现这一点的其他人来说,解决方案实际上非常简单。设置帖子的正文如下:
let body = `username=${username}&password=${password}`;`
请参阅下面的Brad示例。
答案 0 :(得分:80)
您可以使用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}`;
您需要设置标题选项,如下所示:
this.http.post(this.loginUrl, body, { headers: headers }).map(...);
答案 1 :(得分:70)
对于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使其按预期工作的事情:
注意:旧浏览器确实需要填充!我使用了:npm i url-search-params-polyfill --save
然后添加到polyfills.ts:import 'url-search-params-polyfill';
答案 2 :(得分:29)
对于那些仍在寻找答案的人来说,这就是我用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);
NOT 设置Content-Type标头,angular会为您解决此问题!
答案 3 :(得分:11)
这是我在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);
答案 4 :(得分:0)
我在这个问题上工作了几个小时后才找到解决方案
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);
}));
}
答案 5 :(得分:0)
伙计们我已经从事此工作已有一段时间了,多亏了Josh Morony https://www.joshmorony.com/integrating-an-ionic-application-with-a-nodejs-backend/的这篇帖子,我才知道问题出在哪里。基本上,当我开始测试我的api时,我使用的是POSTMAN,并且运行良好,但是当要使用Ionic Angular实现它时,就成了一个问题。这篇文章中的解决方案仅涉及导入body-parser
并将其用作服务器中间根文件(索引)上的app.use(bodyParser.json())
这样的应用中间件。
希望这会有所帮助,谢谢!
答案 6 :(得分:0)
使用角度形式时,大多数参数将作为对象发送,因此您的登录功能很可能具有该对象
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);
}
答案 7 :(得分:0)
const headers = new HttpHeaders({
'Content-Type': 'application/x-www-form-urlencoded'
});
const params = new HttpParams();
params.set('username', 'username');
params.set('password', 'password');
this.http.post(
'https://localhost:5000/api',
params.toString(),
{ headers }
);
答案 8 :(得分:0)
export class MaintenanceService {
constructor(private http: HttpClient) { }
//header de requete http
private headers = new HttpHeaders(
{ 'Content-Type': 'application/x-www-form-urlencoded' }
);
// requete http pour recuperer le type des maintenances
createMaintenance(data: createMaintenance){
const options = { headers: this.headers};
return this.http.post('api/v2/admin/maintenances', data, options ).subscribe(status=> console.log(JSON.stringify(status)));
}
答案 9 :(得分:0)
角度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;
}
)
);
从字符串中记住您使用的是fromString
,而不是fromObject
。