Ajax:修訂版本之間的差異

出自六年制學程
跳轉到: 導覽搜尋
對應的後台程式 upload.php
一、無 form 標籤
第 108 行: 第 108 行:
 
#將上傳檔放到 ./upload/ 路徑下
 
#將上傳檔放到 ./upload/ 路徑下
 
#並以 echo 回應成功或失敗,但此回應不會反映在前台程式執行上,因為前台沒有要處理回應
 
#並以 echo 回應成功或失敗,但此回應不會反映在前台程式執行上,因為前台沒有要處理回應
 +
===二、ajax===
 +
<pre><body>
 +
<form>
 +
<label for="">上傳檔案</label>
 +
<input type="file" id="picture" />
 +
<input type="button" value="確認提交" onclick="confirm()">
 +
</form>
 +
<script>
 +
function confirm(e){
 +
var xmlHttp;
 +
if(window.XMLHttpRequest){
 +
xmlHttp = new XMLHttpRequest();
 +
}else{
 +
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
 +
}
 +
//構造FormData物件
 +
var formData = new FormData();
 +
//新增非檔案資料
 +
formData.append("username","123456");
 +
formData.append("password","67890");
 +
//新增檔案資料
 +
formData.append("picture",document.getElementById("picture").files[0])
 +
//使用POST方法傳送資料
 +
xmlHttp.open("POST","/imageUpload",true);
 +
xmlHttp.send(formData)
 +
//返回的資料
 +
xmlHttp.onreadystatechange=function(){
 +
if (xmlHttp.readyState==4 && xmlHttp.status==200){
 +
console.log(xmlHttp.responseText);
 +
}
 +
}
 +
}
 +
</script>
 +
</body></pre>
 +
已後送:
 +
<pre>{
 +
username:123456,
 +
password:67890,
 +
picture:檔案資料(其實這裡是將檔案轉換為二進位制了)
 +
}</pre>
 +
使用FormData後,會將request的Content-Type設定為
 +
<pre>“multipart/form-data;boundary=----" 一段隨機的字母;</pre>
 +
上面的boundary正如字面的意思一樣,就是一個分界的意思,分開每一個鍵值對資料,具體的資料格式為
 +
<pre>--boundary(換行)
 +
Content-Disposition:form-data;name=“資料的鍵”(換行)
 +
\r\n(換行)
 +
資料的值(“換行”)</pre>
 +
每一個boundary的前面要加兩個“-”
 +
對於檔案的資料格式為:
 +
<pre>--boundary
 +
Content-Disposition:form-data;name="username"
 +
\r\n
 +
123456
 +
--boundary
 +
Content-Disposition:form-data;name="password"
 +
\r\n
 +
67890
 +
--boundary
 +
Content-Disposition:form-data;name="picture";filename="上傳的檔名"
 +
\r\n
 +
Content-Type:image/jpeg;
 +
對圖片進行二進位制編碼後的資料
 +
--boundary--</pre>

2022年6月28日 (二) 22:51的修訂版本

HTTP 中的 Content-Type: multipart/form-data

常見的傳輸格式:

  1. Content-Type: application/json 代表請求內容是 JSON
  2. Content-Type: image/png 代表請求內容是圖片檔
  3. Content-Type: multipart/form-data 使用 (RFC7578) 規範,用一個請求傳送複數個資料格式,主要用於表單或實作檔案上傳。可以用 HTML 的 form 標籤指示 enctype='multipart/form-data' 屬性(配合 Submit),或 JavaScript 的 FormData 類別(配合 onclick)。
    • multipart/form-data 也是 HTTP 請求的一種
    • 只要符合格式不用瀏覽器也可以發送請求
    • 請求只是將一坨二進制數傳至伺服器,檔案內容必須在伺服器端解析
  4. 表單當中使用 GET 方法送出,那麼所有表單的內容都以 url encoded 的方式被傳送。HTML 點擊 Submit 按鈕後會變成「請求目的地?name=變數值&file=變數值」,就算 enctype 指定 multipart/form-data 還是會以「 application/x-www-form-urlencoded」的形式送出。
以下先看瀏覽器發送的一個 HTTP POST multipart/form-data 請求:
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 的作用與格式:

  1. 指示每個資料的界限在哪裡
  2. boundary 的格式:
    • 開頭是兩個 hypen
    • 總長度在 70 以內(不包含 hypen 本身)
    • 只接受 ASCII 7bit
    • 最後一個 boundary 則會再以兩個 hypen 當作結尾
  3. 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
      空白行
      圖檔二進制內容

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 ,可以使得本應移到程式碼的最後方,等到所有的原始碼運行完以後才會執行非同步的事件,如同步事件一樣先被執行:
    1. async function 可以用來定義一個非同步函式,讓這個函式本體是屬於非同步,但其內部以「同步的方式運行非同步」程式碼。
    2. await 則是可以暫停非同步函式的運行(中止 Promise 的運行),直到非同步進入 resolve 或 reject,當接收完回傳值後繼續非同步函式的運行。
  • let 宣告的變數生命週期只在區塊之內
  • formData.append(欄位, 欄值);
  • fetch(後送請求目地的,後送選項)
    1. 後送選項是一個物件,包含怎麼後送、後送什麼兩個項

對應的後台程式 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'; 
}

?>
  1. 將上傳檔放到 ./upload/ 路徑下
  2. 並以 echo 回應成功或失敗,但此回應不會反映在前台程式執行上,因為前台沒有要處理回應

二、ajax

<body>
<form>
<label for="">上傳檔案</label>
<input type="file" id="picture" />
<input type="button" value="確認提交" onclick="confirm()">
</form>
<script>
function confirm(e){
var xmlHttp;
if(window.XMLHttpRequest){
xmlHttp = new XMLHttpRequest();
}else{
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
//構造FormData物件
var formData = new FormData();
//新增非檔案資料
formData.append("username","123456");
formData.append("password","67890");
//新增檔案資料
formData.append("picture",document.getElementById("picture").files[0])
//使用POST方法傳送資料
xmlHttp.open("POST","/imageUpload",true);
xmlHttp.send(formData)
//返回的資料
xmlHttp.onreadystatechange=function(){
if (xmlHttp.readyState==4 && xmlHttp.status==200){
console.log(xmlHttp.responseText);
}
}
}
</script>
</body>

已後送:

{
username:123456,
password:67890,
picture:檔案資料(其實這裡是將檔案轉換為二進位制了)
}

使用FormData後,會將request的Content-Type設定為

“multipart/form-data;boundary=----" 一段隨機的字母;

上面的boundary正如字面的意思一樣,就是一個分界的意思,分開每一個鍵值對資料,具體的資料格式為

--boundary(換行)
Content-Disposition:form-data;name=“資料的鍵”(換行)
\r\n(換行)
資料的值(“換行”)

每一個boundary的前面要加兩個“-” 對於檔案的資料格式為:

--boundary
Content-Disposition:form-data;name="username"
\r\n
123456
--boundary
Content-Disposition:form-data;name="password"
\r\n
67890
--boundary
Content-Disposition:form-data;name="picture";filename="上傳的檔名"
\r\n
Content-Type:image/jpeg;
對圖片進行二進位制編碼後的資料
--boundary--