使用ANGULAR2的HTTP傳送AJAX請求
使用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();
}
}