Ajax:修訂版本之間的差異
出自六年制學程
(→三、用 iframe 配合 target 使 form 後送不翻頁) |
(→二、用 ajax 不用 fetch) |
||
第 108 行: | 第 108 行: | ||
#將上傳檔放到 ./upload/ 路徑下 | #將上傳檔放到 ./upload/ 路徑下 | ||
#並以 echo 回應成功或失敗,但此回應不會反映在前台程式執行上,因為前台沒有要處理回應 | #並以 echo 回應成功或失敗,但此回應不會反映在前台程式執行上,因為前台沒有要處理回應 | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
===二、用 iframe 配合 target 使 form 後送不翻頁=== | ===二、用 iframe 配合 target 使 form 後送不翻頁=== | ||
<pre><?php | <pre><?php |
2022年6月29日 (三) 07:28的修訂版本
目錄
HTTP 中的 Content-Type: multipart/form-data
常見的傳輸格式:
- Content-Type: application/json 代表請求內容是 JSON
- Content-Type: image/png 代表請求內容是圖片檔
- Content-Type: multipart/form-data 使用 (RFC7578) 規範,用一個請求傳送複數個資料格式,主要用於表單或實作檔案上傳。可以用 HTML 的 form 標籤指示 enctype='multipart/form-data' 屬性(配合 Submit),或 JavaScript 的 FormData 類別(配合 onclick)。
- multipart/form-data 也是 HTTP 請求的一種
- 只要符合格式不用瀏覽器也可以發送請求
- 請求只是將一坨二進制數傳至伺服器,檔案內容必須在伺服器端解析
- 表單當中使用 GET 方法送出,那麼所有表單的內容都以 url encoded 的方式被傳送。HTML 點擊 Submit 按鈕後會變成「請求目的地?name=變數值&file=變數值」,就算 enctype 指定 multipart/form-data 還是會以「 application/x-www-form-urlencoded」的形式送出。
POST 目的地 HTTP/1.1 Host: localhost:3000 Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryFYGn56LlBDLnAkfd User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36 ------WebKitFormBoundaryFYGn56LlBDLnAkfd Content-Disposition: form-data; name="name" Test ------WebKitFormBoundaryFYGn56LlBDLnAkfd Content-Disposition: form-data; name="file"; filename="text.txt" Content-Type: text/plain Hello World ------WebKitFormBoundaryFYGn56LlBDLnAkfd--
boundary 的作用與格式:
- 指示每個資料的界限在哪裡
- boundary 的格式:
- 開頭是兩個 hypen
- 總長度在 70 以內(不包含 hypen 本身)
- 只接受 ASCII 7bit
- 最後一個 boundary 則會再以兩個 hypen 當作結尾
- boundary 之下的處理:
- Content-Disposition: form-data; name="欄名"
空白行
欄位內容 - 如果是檔案:
Content-Disposition: form-data; name="欄名"; filename="檔名"
Content-Type: text/plain
空白行
欄位內容(同時也是檔案內容) - 如果是圖片檔或是其他非文字檔(舉 png 圖檔為例):
Content-Disposition: form-data; name="file"; filename="image.png"
Content-Type: image/png
空白行
圖檔二進制內容
- Content-Disposition: form-data; name="欄名"
FormData 類別
資料後送
etable 舊版
檔案上傳程式範例
一、無 form 標籤
前台程式
<!DOCTYPE html> <html> <head> <title> Ajax JavaScript File Upload Example </title> </head> <body> <!-- HTML5 Input Form Elements --> <input id="fileupload" type="file" name="formData" /> <button id="upload-button" onclick="uploadFile()"> Upload </button> <!-- Ajax JavaScript File Upload Logic --> <script> async function uploadFile() { let formData = new FormData(); formData.append("file", fileupload.files[0]); await fetch('./upload.php', { method: "POST", body: formData }); alert('The file has been uploaded successfully.'); } </script> </body> </html>
- 表單元素沒有 form 標籤、沒有 action 指示,被請求的後台程式完全靠 javascript 的 fetch ,執行時也不會將後台程式的回應顯示取代目前的頁。
- 兩個表單元素:一個負責讓使用者選上傳檔,另一個負責驅動 javascript 的 uploadFile() 函式
- async 非同步函式配合 await ,可以使得本應移到程式碼的最後方,等到所有的原始碼運行完以後才會執行非同步的事件,如同步事件一樣先被執行:
- async function 可以用來定義一個非同步函式,讓這個函式本體是屬於非同步,但其內部以「同步的方式運行非同步」程式碼。
- await 則是可以暫停非同步函式的運行(中止 Promise 的運行),直到非同步進入 resolve 或 reject,當接收完回傳值後繼續非同步函式的運行。
- let 宣告的變數生命週期只在區塊之內
- formData.append(欄位, 欄值);
- fetch(後送請求目地的,後送選項)
- 後送選項是一個物件,包含怎麼後送、後送什麼兩個項
對應的後台程式 upload.php
<?php /* Get the name of the uploaded file */ $filename = $_FILES['file']['name']; /* Choose where to save the uploaded file */ $location = "./upload/".$filename; /* Save the uploaded file to the local filesystem */ if ( move_uploaded_file($_FILES['file']['tmp_name'], $location) ) { echo 'Success'; } else { echo 'Failure'; } ?>
- 將上傳檔放到 ./upload/ 路徑下
- 並以 echo 回應成功或失敗,但此回應不會反映在前台程式執行上,因為前台沒有要處理回應
二、用 iframe 配合 target 使 form 後送不翻頁
<?php // 前置處理 if($_POST['button']=='更新'){ $filename = $_FILES['f']['name']['etTest']['ABC']['fileName']; if(move_uploaded_file($_FILES['f']['tmp_name']['etTest']['ABC']['fileName'], "./upload/".$filename)){ echo 'Success'; }else{ echo 'Failure'; } }else{ $str="<!DOCTYPE html> <html> <head> <meta charset='UTF-8'/> <title> Ajax JavaScript File Upload Example </title> </head> <body> <!-- HTML5 Input Form Elements --> <form target='list' enctype='multipart/form-data' name='col_form' id='col_form' method='post' onsubmit='return xoopsFormValidate_col_form();' > 路徑: <select size='1' name='f[etTest][ABC][path]' id='f[etTest][ABC][path]'> <option value='1'>丁丁</option> <option value='2'>丁禾</option> </select> <input type='checkbox' name='f[etTest][DEF][]' id='f[etTest][DEF][1]' value='1'/> <input type='checkbox' name='f[etTest][DEF][]' id='f[etTest][DEF][2]' value='2'/> 請選檔: <input type='file' name='f[etTest][ABC][fileName]' id='f_etTest_ABC_fileName'/> <button name='button' value='更新' onclick=\"uploadFile('col_form','list');\"> 更新 </button> </form> <!-- Ajax JavaScript File Upload Logic --> <script> async function uploadFile(formID,divID){ let formData = new FormData(document.getElementById(formID)); await fetch('".$_SERVER['PHP_SELF']."', {method: 'POST',body: formData}).then((response) => {return response.text();}).then((responseText)=> {document.getElementById(divID).innerHTML=responseText;}); } </script> <iframe id='list' name='list'></iframe> </body> </html>"; echo $str; } ?><pre>