# AJAX筆記
## 0. 目錄
前端javscript的API的3種寫法:
1. XMLHttpRequest
2. (用Jquery)AJAX
3. fetch(部分舊瀏覽器不支援)
## 0.1 AJAX說明
- AJAX即「Asynchronous JavaScript and XML」(非同步的JavaScript與XML技術)
- AJAX應用程式可以僅向網頁伺服器傳送並取回必須的資料,並在瀏覽器端使用JavaScript處理來自伺服器的回應。
- 因在網頁伺服器和瀏覽器之間交換的資料大量減少,網頁伺服器的回應就更快速了。
- 同時很多處理工作可以在發出請求的瀏覽器端機器上完成,因此網頁伺服器的負荷也可以減少。
#### 非同步請求相較於同步請求的優點
- 瀏覽器發送同步請求(Synchronous Request)時,必須等候網頁伺服器的回應(Response)完成之後才能繼續網頁程式的執行,如此,瀏覽器視窗的畫面有時可能會出現凍結(freezing)現象,因而造成不及時響應(unresponsive)的使用者經驗。
## 1. XMLHttpRequest
### 1.1 XMLHttpRequest- Get範例
```javascript=
$("#b2").click(function () {
var xhr = new XMLHttpRequest();
//open後第一個參數是Action,第二個是data(字串帶在查詢參數),第三個是否為非同步傳輸(設定為true)。
xhr.open("get", "data/Emp.json", true);
// onreadystatechange 4代表已經收到伺服器回應
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) { //The operation is complete.
if (xhr.status === 200) {//The HTTP status is 200(ok)
$("#div2").html(`來自伺服器的回應:<br/> ${xhr.responseText}`);
} else {
$("#div2").html(`<span class="text-danger">來自伺服器的回應:${xhr.status} ${xhr.statusText}</span>`);
}
}
};
xhr.send(null);
});
```
### 1.2 XMLHttpRequest- POST範例
```javascript=
$("#form1").submit(function () {
var xhr = new XMLHttpRequest();
xhr.open("post", "login", true); //true表示非同步請求。
//當接收到server資料時
xhr.onload = function () {
if (xhr.status === 200) {
if (xhr.responseText == 'pass')
$("#msg1").html(`<span class="text-primary">恭喜!您已通過身份驗證。</span>`);
else
$("#msg1").html(`<span class="text-danger">抱歉!您未通過身份驗證。</span>`);
} else {
$("#msg1").html(`<span class="text-danger">${xhr.status} ${xhr.statusText}</span>`);
}
setTimeout(function(){$("#msg1").html("")}, 2000);
};
//準備表單資料
//方法一
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8") //預設Content-Type: text/plain;charset=UTF-8
var formData = $(this).serialize(); //formData如: username=%E5%B0%8F%E5%80%A9&password=%E9%87%87%E8%87%A3
//方法二
//var formData = new FormData(this); //此招勿設定Content-Type標頭
xhr.send(formData);
return false;
});
```
### 1.3 請解釋XMLHttpRequest
XMLHttpRequest.onreadystatechage:
XMLHttpRequest.onreadystatechagereadyState:
XMLHttpRequest.onload

XMLHttpRequest.status:
XMLHttpRequest.statusText:
XMLHttpRequest.responseText:

### 1.4 XMLHttpRequest傳json
前端送資料給後端by json

------
## 2. AJAX
### 2.1 AJAX用法-Get
Data:前端送去給後端的東西
success: function中的data是後端送給前端的json
#### 前端接收後端送來的json

#### 後端的送法使用匿名物件
```csharp=
return new{greeting:"測試字串"}
```
### 2.2 AJAX用法-Post檔案
```javascript=
$("#form2").submit(function (event) {
event.preventDefault();
$.ajax({
async: true,
method: 'post',
url: $(this).attr('action'),
data: new FormData(this),//只適用於post方法
//contentType: 預設'application/x-www-form-urlencoded; charset=UTF-8',
contentType: false, //required for「formData = new FormData(this)」
processData: false, //required for「formData = new FormData(this)」
beforeSend: function () {
var ans = confirm("您確定要上傳檔案嗎?");
if (ans)
return true;
else
return false;
},
success: function (data) {
$("#msg2").html(`<span class="text-success">${data}<span>`);
},
error: function (jqXHR, textStatus, errorThrown) {
$('#msg2').html(`<span class="text-danger">${textStatus} ${jqXHR.status} ${errorThrown}<br/>${jqXHR.responseText}<span>`);
},
complete: function () {
setTimeout(function(){$("#msg2").html(''); }, 3000);
}
});
});
```
#### 說明
$(this).serialize()方法把表單的數據序列化成URL編碼的字符串,並附加在URL的查詢字串部分,如"?username=小倩&password=采臣"。這樣伺服器就可以解析這些參數,從而進行身分驗證。
##### 說明載入文字檔

當使用者選擇一個新檔案時,會呼叫 previewImg() 函式預覽新圖片。此函式會接收到使用者所選的檔案 (即 this.files),如果該檔案不存在就會直接返回。接著,我們從該檔案建立一個 FileReader() 物件 fr,並註冊一個事件處理器 onload,在該檔案讀取完成後呼叫這個事件處理器。在事件處理器中,我們將讀取到的檔案內容轉換成一個 data URL 字串,並將這個字串設定為圖片元素的 src 屬性值。這樣就能夠預覽使用者所選的圖片。
接下來的程式碼是使用Ajax模式上傳檔案。當表單被提交時,防止表單的默認行為,即重新加載頁面,使用$ .ajax()函數以非同步方式向伺服器發送HTTP請求。在此範例中,使用POST方法向伺服器發送請求,並且指定url屬性為表單的action屬性,data屬性為使用new FormData()函數構造的新表單數據,contentType屬性設置為false,以確保表單數據以multipart/form-data格式傳送,processData屬性設置為false,以防止$.ajax()將數據轉換為查詢字符串。
```javascript=
function previewImg(files) {
if (files.length == 0)
return;
var file = files[0];
var fr = new FileReader();
//註冊:選檔被讀取完成後之事件處理器
fr.onload =
function () {
$("#img1").attr({ src: fr.result });
/* fr.result: The file's contents. 內容如下:
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA ...
*/
};
fr.readAsDataURL(file);
}
```
### 非同步上傳檔案(後端)

### 2-3 Ajax登入方法
```javascript=
<script>
function sendAjaxRequest(url, username, password) {
return new Promise(
function (resolve, reject) { //executor
//非同步操作
$.ajax({
method: 'post',
url: url,
data: { username, password },
dataType:'text',
success: function (data) {
resolve(data);
},
error: function (jqXHR, textStatus, errorThrown) {
reject(`${textStatus} ${jqXHR.status} ${errorThrown}`);
}
});
});
}
//------------------------------------------------------//
$("#a3").click(function () {
let username = "小倩";
let password = "采臣";
sendAjaxRequest('login', username, password)
.then(
function (data) {
if(data=='pass'){
$("#div3").append(`<div class="text-primary my-2">「${username}」已通過網頁伺服器的身份驗證...</div>`);
// 原來這裡又丟了一個welcome
return sendAjaxRequest('welcome', username);
}
else
throw `抱歉!「${username}」未通過身份驗證。`;
}
)
.then(
// xx的welcome在哪裡?
function (text) {
let obj = JSON.parse(text);
$("#div3").append(`<div class="text-primary my-2">網頁伺服器回應:${obj.greeting}</div>`);
}
)
.catch(function (err) {
$("#div3").append(`<div class="text-danger my-2">${err}</div>`);
}); //catch(failureCallback) 是 then(null, failureCallback) 的簡寫
return false;
});
</script>
```
#### 補充:Promise

## 3. fetch
### 3.1 fetchAPI-Get
### 3.2 fetchAPI-Post
### 3.3 fetchAPI-Post
```javascript=
$("#form1").submit(function () {
fetch('login', {
method: 'POST', //預設'GET' (POST方法才可設定body)
body: $(this).serialize(), //$(this).serialize()之值如: username=%E5%B0%8F%E5%80%A9&password=%E9%87%87%E8%87%A3
//亦可如body:'username=小倩&password=采臣',
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8'
//當使用者設定了body為query string時,Content-Type會自動被設為text/plain;charset=UTF-8
}
})
//fetch()回傳的Promise 基本上不會被Rejected (除了網路發生問題)。
.then(function (response) {
if (response.ok) //response.ok:true表示HTTP狀態碼為200~299
return response.text();
else
throw new Error(`${response.status} ${response.statusText}`);
})
.then(function (text) {
if (text == "pass")
$("#msg1").html(`網頁伺服器回應: <span class="text-primary">${text}</span>`);
else
$("#msg1").html(`網頁伺服器回應: <span class="text-danger">${text}</span>`);
setTimeout(function () { $("#msg1").html(""); }, 3000);
})
.catch(function (err) {
$("#msg1").html(`<span class="text-danger">Ajax請求發生錯誤: ${err}</span>`);
setTimeout(function () { $("#msg1").html(""); }, 3000);
});
return false;
});
```
## 4. CROS允許同樣IP來源不同Port設定
CORS(Cross-Origin Resource Sharing)是一個安全機制,用於限制跨網域的資源請求。在網頁開發中,如果網頁或應用程式需要從不同的網域或端口請求資源,就需要使用CORS。
CORS的基本原則是,瀏覽器只會允許網頁或應用程式從同一網域發出的請求,而不允許從不同網域發出的請求。這是出於安全考慮,以避免跨站點腳本攻擊(XSS)和跨站點偽造請求攻擊(CSRF)等安全風險。
```csharp=
builder.Services.AddCors(
corsOptions =>
{
corsOptions.AddDefaultPolicy(
policy =>
{
policy.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader();
//policy.WithOrigins("https://localhost:7219", "http://localhost:5219").WithMethods("get", "post", "put", "delete").WithHeaders("content-type");
}
);
}
);
```