使用Angular2的Http发送AJAX请求
Angular的文档并不详细,甚至API文档也有一些错误。经过查阅资料并经大量实验,终于明确了Angular的Http发送Ajax请求的方式方法。本文描述了通过Angular的Http发送Ajax请求相关的全部内容。请各位同事仔细阅读并付诸实践。
1. Angular的Http类
Angular的Http类负责与服务端通讯,通过Ajax的形式访问远程服务器。
Angular的Http访问远程服务器,可以使用GET、POST、PUT、DELETE、OPTIONS等方法(method)。
当然,我们最常使用的是GET和POST方法。
当Angular发现你所访问的地址是跨域的,会自动发送一次OPTIONS方法的请求,确定此跨域服务器是否支持跨域访问。若不支持跨域访问,则给出错误,不能执行真正的GET、POST请求。
2. 使用Angular发送GET请求
// 以下是一些必须的导入
import { Http, URLSearchParams,RequestOptions } from '@angular/http'; // 发送请求有关的类
import { Observable } from "rxjs"; // 明确请求后的可观察对象是Rx的可观察对象,如未指明是Rx的可观察对象,会报错。
import 'rxjs/add/operator/toPromise'; // 引入toPromise操作符,否则会报错,toPromise方法未定义。
// 发送get请求的方法
get() : Promise<string> {
let serverurl: string = "url地址";
// 创建请求参数对象,所有请求参数被放在此对象中。
let param = new URLSearchParams();
param.append("param1","test"); // 向请求参数中放入参数及值
// 创建请求设置对象,将请求参数作为其构造方法参数对象的"search"属性值。
// 请注意,在这里我们并未明确请求头(Headers),Angular会根据请求方法(method)
// 及请求参数的类型,自动确定请求头类型。
let options = new RequestOptions({search:param});
// 发起get请求。注意http属性必须由依赖注入而来。
return this.http.get(serverurl, options)
.toPromise() // 将可观察对象转为承诺,接下来按照承诺的方式处理。
.then(response => {
let data = response.json();
if (data.is_ok == 2) {
let result:string = data.rs;
console.log(result);
return Promise.resolve(result);
}
return Promise.reject("false");
}).catch(error => {
console.log(error);
return Promise.reject("false");
});
}
3. 使用Angular发送POST请求
// 以下是一些必须的导入
import { Http, URLSearchParams,RequestOptions } from '@angular/http'; // 发送请求有关的类
import { Observable } from "rxjs"; // 明确请求后的可观察对象是Rx的可观察对象,如未指明是Rx的可观察对象,会报错。
import 'rxjs/add/operator/toPromise'; // 引入toPromise操作符,否则会报错,toPromise方法未定义。
// 发送Post请求的方法
postByForm(): Promise<string> {
let serverurl: string = "url地址";
// 创建请求参数对象,所有请求参数被放在此对象中。
let param = new URLSearchParams();
param.append("param1","test"); // 向请求参数中放入参数及值
// 发起Post请求(http属性必须由依赖注入而来),请注意,post方法比get方法多了一个参数,多的是第2个参数。
// 第1个参数是url地址,第2个参数是请求参数;
// 第3个参数对应get方法的第2个参数,是请求设置(RequestOptions)对象。
// 在get请求中,我们将请求参数(URLSearchParams)放在了请求设置的(RequestOptions)对象的"search"属性中,
// 在post方法中,post请求参数作为post方法的第2个参数,不能放到请求设置的(RequestOptions)对象的"search"属性中。
// 如放到了请求设置的(RequestOptions)对象的"search"属性中,则被作为请求get参数的一部分。
// 如:url地址?param1=test,
// 这不是我们想要的。我们使用了post方法,即是希望在请求体的form-data部分传输我们的参数,
// 而不希望请求参数出现在url地址上。
// 在这里,请求设置对象是个null,因为我们不需要给本次请求设置请求头,请求头由anglar自动计算。
return this.http.post(serverurl, param, null)
.toPromise()
.then(response => {
let data = response.json();
if (data.is_ok == 2) {
let result:string = data.rs;
console.log(result);
return Promise.resolve(result);
}
return Promise.reject("false");
}).catch(error => {
console.log(error);
return Promise.reject("false");
});
}
4. 使用Angular以FormData对象作为参数发送POST请求
FormData是 XMLHttpRequest Level 2 新增的一个对象,在IE10及以上版本受支持,其他浏览器的新版本基本都支持。
FormData的结构就是一组键值对,键名是参数名,键值是参数值。它最大的特点是支持二进制流,所以我们使用FormData主要是用AJAX技术上传文件。上传文件时,文件是FormData中的一组键值对,除了文件以外的参数,也可以被放到FormData中一并提交给服务器。
// 以下是一些必须的导入
import { Http, URLSearchParams,RequestOptions } from '@angular/http'; // 发送请求有关的类
import { Observable } from "rxjs"; // 明确请求后的可观察对象是Rx的可观察对象,如未指明是Rx的可观察对象,会报错。
import 'rxjs/add/operator/toPromise'; // 引入toPromise操作符,否则会报错,toPromise方法未定义。
// 发送Post请求的方法
postByFormData(): Promise<string> {
let serverurl: string = "url地址";
let param = new FormData();
// 放入要上传的文件
let file = this.fileElement.nativeElement.files[0];
param.append("file",file);
// 放入其他参数
param.append("param1","test");
// 发送post请求(http属性必须由依赖注入而来),可以看到,除了第二个参数param的类型为FormData外,其余参数与普通post请求一致。
// angular会自动计算请求头类型。
return this.http.post(serverurl, param, null)
.toPromise()
.then(response => {
let data = response.json();
if (data.is_ok == 2) {
let result:string = data.rs;
console.log(result);
return Promise.resolve(result);
}
return Promise.reject("false");
}).catch(error => {
console.log(error);
return Promise.reject("false");
});
}
5. 服务器端的处理
5.1 接收参数
后台程序接收参数的方式方法与传统接收参数的方式方法完全一致。这里以PHP和Java程序举例:
// php
$param1 = $_GET['param1'];
// j2ee servlet
String param1 = request.getParameter("param1");
// java struts
private String param1;
public getParam1(){
return param1;
}
public setParam1(String param1){
this.param1 = param1;
}
public String execute(){
System.out.println(param1);
return SUCCESS;
}
若客户端传入了文件流,则按照传统方式获得文件即可。
5.2 跨域访问
当Angular发起跨域Ajax请求时,会自动发送一次OPTIONS方法的请求,确定此跨域服务器是否支持跨域访问,服务端程序应对此请求进行特殊处理,使OPTIONS方法的请求不执行真正的业务处理,并告知客户端允许跨域。
不执行真正的业务处理,是为了防止由于两次请求而导致的重复业务操作。
告知客户端允许跨域,是为了通知Angular可以执行接下来真正的Post、Get或其他方法的请求。
以上两点必须都被正确实现和处理!
这里以Java Servlet程序为例。
<!-- web.xml,正确的添加过滤器 -->
<!-- 允许AJAX跨域请求,处理OPTION请求。该过滤器必须在其他过滤器之前定义,也就是说,当请求到达服务器,首先由此过滤器处理后,如需过滤器链中后续的过滤器继续处理,才能执行此过滤器后面的过滤器。 -->
<!-- 若顺序错误,则无法实现上述第1点(不执行真正的业务处理)。 -->
<filter-mapping>
<filter-name>ACAO-option</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>ACAO-option</filter-name>
<filter-class>包名.ACAOFilter</filter-class>
</filter>
// ACAOFilter
public class ACAOFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
if(!(request instanceof HttpServletRequest)){
chain.doFilter(request, response);
}
HttpServletRequest req = (HttpServletRequest)request;
String method = req.getMethod();
HttpServletResponse res = (HttpServletResponse)response;
// 向响应头中添加3个关键值。
// 请注意,这3个关键值无论请求方法是否为OPTIONS都要添加。
// 若没有添加这3个关键值,则Angular发起真实的GET和POST请求时,仍会接到错误通知:“服务器不允许跨域”。
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTION");
res.setHeader("Access-Control-Allow-Headers", "x-requested-with,content-type");
// 如果不是OPTIONS方法的请求,过滤器链继续执行。否则结束。
if(!"OPTIONS".equals(method)){
chain.doFilter(request, response);
}
}
public void init(FilterConfig filterConfig) throws ServletException {
}
public void destroy() {
}
}
/**
* php允许跨域访问。并返回是否需要继续处理。
*/
public static function allowOriginRequest():void{
header('Access-Control-Allow-Origin:*');
$method = $_SERVER['REQUEST_METHOD'];
if(strtoupper($method) == "OPTIONS"){
exit();
}
}