基礎知識
JQuery AJAX: contentType
- 不填寫時,預設為 application/x-www-form-urlencoded。
FormData
- 
FormData 介面可為表單資料中的欄位/值建立相對應的的鍵/值對(key/value)集合,之後便可使用 XMLHttpRequest.send()方法來送出資料。
- 
它在編碼類型設定為 multipart/form-data時會採用與表單相同的格式送出。
RFC1867
剛開始,http 協議中没有檔案上傳的功能,直到 RFC1867 為 http 協議添加了此功能。
在 RFC1867 中限定:
- 
<form>的method必須是POST。
- 
enctype屬性新增了multipart/form-data的選項。
- 
<input>的type屬性增加了file選項。
程式碼
html
<form action="server/api/items" name="productForm" enctype="multipart/form-data" method="POST">
  <h3>新增商品</h3>
  <input type="file" name="files" class="productFile">
  <input type="text" class="productName">
  <input type="number" min="1" class="productPrice">
  <input type="submit" value="送出">
</form>
JavaScript
// 取得表單
let productForm = document.forms.namedItem('productForm')
productForm.addEventListener('submit', function(event){
    post_items(event, productForm)
})
function api_post_items (event, form){
  // 取消表單預設提交
  event.preventDefault()
  
  let name = document.querySelector('.productName').value
  let stock = document.querySelector('.productAmount').value
  let unit_price = document.querySelector('.productPrice').value
  let file = $('.productFile')[0].files[0] // 單個檔案
  // 建立一個新的 FormData 物件
  let formData = new FormData(form)
  // 追加新值到 FormData 物件已有的對應鍵上;若該鍵不存在,則為其追加新的鍵
  formData.append('name', name)
  formData.append('cost', cost)
  formData.append('unit_price', unit_price)
  formData.append('images', file)
  let item = {
    'url': `${ server }/api/items`,
    'type': 'POST',
    'headers': {
      // 'Content-Type': 'multipart/form-data',
      // 使用 multipart/form-data 在此不需要設定 Content-Type。
      'X-Requested-With': 'XMLHttpRequest',
      'Authorization': `Bearer ${ userToken }`,
    },
    'contentType': false, //required
    'processData': false, // required
    'mimeType': 'multipart/form-data',
    'data': formData
  }
    $.ajax(item)
      .done(function (response) {
        console.log(response)
        closeLightBox()
        api_get_items()
      })
      .fail(function (response) {
        console.log('api_post_user: Fail ' + response.responseText)
      })
  }
注意!
- 
在 <form>表單設定enctype="multipart/form-data"。
- 
<form>中,需要有<input type="file">。
- 
JavaScript中 設定contentType = false。- 在傳送 multipart/formdata時,希望不影響原表單設定,而直接將預設值改為multipart/form-data。
 
- 在傳送 
- 
JavaScript中 設定processData = false。- 不去處理資料。
 
- 
JavaScript中 設定cache = false,檔案不需緩存。
表單送出後,去檢查 Request Headers 看到我們有帶 boundary 成功傳輸。
Reference
FormData - MDN
Content-Type - MDN
通过jQuery Ajax使用FormData对象上传文件
浅谈contentType = false
从FormData到图片上传
Submitting multipart/form-data using jQuery and Ajax
missing boundary in Content-Type for multipart posts
留言