一個 form post 也可以繞個一大圈 |
網頁傳統 form 要傳遞參數值時,會使用 action,寫法大致如下:
<form action="http://localhost:8080/login" method="post">
<h1>Form Action Test</h1>
<input type="text" name="email" value="Eden" />
<input type="password" name="password" value="L@veEden" />
<input type="submit" value="Submit">
</form>
可以看到 submit 時,Request 的 Content-Type 屬性是很標準的 application/x-www-form-urlencoded。
這個方式很標準,絕大部份的 Web Server 都可以接受,當然也包含了 Delphi Web Server。
時代在進步,JavaScript 標準都來到 2020,所以當然要試一下新的操作方法。
JavaScript 裡有 FormData 類別,可以建構 form 物件,寫法如下:
<form id="login-form" onsubmit="handleSubmit(event)">
<input type="text" name="email" value="Eden" />
<input type="password" name="password" value="L@veEden" />
<input type="submit" value="Submit">
</form>
<script>
function handleSubmit(event) {
event.preventDefault()
let formData = new FormData(document.getElementById('login-form'))
fetch("http://localhost:8080/login", {
method: "POST",
body: formData
})
}
</script>
實際 submit 時 Request 的 Content-Type 屬性是 multipart/form-data,如下圖所示:
multipart/form-data 相對於 application/x-www-form-urlencoded 比較少見,故某些 Web Server 預設是不會處理 multipart/form-data 的格式內容。
既然後端需要做調整,如果前端事先做好,那後端不就更省事?
前端調整
仿照傳統規則
前端仿照傳統的作法實作,程式碼如下: <form id="login-form" onsubmit="handleSubmit(event)">
<input type="text" name="email" value="Eden" />
<input type="password" name="password" value="L@veEden" />
<input type="submit" value="Submit">
</form>
<script>
function handleSubmit(event) {
event.preventDefault()
let formElement = document.getElementById("login-form")
let formData = ""
formData = "email=" + formElement[0].value
formData = formData + "&password=" + formElement[1].value
fetch("http://localhost:8080/login", {
method: "POST",
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: formData
})
}
</script>
執行結果
修改後就能讓 Web Server 順利解析參數。
使用 URLSearchParams
URLSearchParams 是個處理各種URL查詢參數轉換的類別,在這個例子只需要將 FormData 再丟入 URLSearchParams 處理過,即能得到 application/x-www-form-urlencoded 所需的查詢參數,程式如下所示:<html>
<head></head>
<body>
<form id="login-form" onsubmit="handleSubmit(event)">
<input type="text" name="email" value="Eden" />
<input type="password" name="password" value="L@veEden" />
<input type="submit" value="Submit">
</form>
<script>
function handleSubmit(event) {
event.preventDefault()
let formData = new FormData(document.getElementById('login-form'))
var searchParams = new URLSearchParams(formData);
fetch("http://localhost:8080/login", {
method: "POST",
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: searchParams
})
}
</script>
</body>
</html>
執行結果
一樣修改後就能讓 Web Server 順利解析參數。
總結
新方法但沿用舊觀念,在某些前端框架看不到的細節還是要拆成香草JS小部件來多做嘗試才行。前端修改下我會偏好使用 URLSearchParams,在開發上比較省力,程式也比較好懂。
以上提供各位參考。謝謝大家收看!
【2021.05.18 更新】
jQuery 和 form 的結合
<html> <head> <script src="https://code.jquery.com/jquery-3.6.0.js" integrity="sha256-H+K7U5CnXl1h5ywQfKtSj8PCmoN9aaq30gDh27Xc0jk=" crossorigin="anonymous"></script> </head> <body> <form id="login-form" onsubmit="handleSubmit(event)"> <input type="text" name="email" value="Eden" /> <input type="password" name="password" value="L@veEden" /> <input type="submit" value="Submit"> </form> <script> function handleSubmit(event) { event.preventDefault() const formData = {user:document.getElementByName("user").value, password:document.getElementByName("password").value} // item 的內容也可以用 $.ajax.beforeSend 替換 const item = { 'url': "http://localhost:8080/login", 'type': 'POST', 'headers': { 'Authorization': `Basic ${ base64Auth }`, }, //'contentType': false, // Default = application/x-www-form-urlencoded //'processData': false, // false = jq 不轉譯 Json to Parameters; Default=True 'data': formData } $.ajax(item) .done(function (response) { console.log(response) }) .fail(function (response) { console.log('Fail : ' + response.responseText) }) } </script> </body> </html>
See also
- RESTful API 練習 (XHR, Fetch詳解)
- MDN-URLSearchParams
- 'x-www-form-urlencoded' or 'form-data' 😵 ? Explained in 2 mins.
- 踩坑篇--使用 fetch 上传文件
- 鐵人賽:ES6 原生 Fetch 遠端資料方法
- 使用 JQuery 透過 FormData 上傳檔案 (headers 帶 boundary)
- Use basic authentication with jQuery and Ajax
- Should I use .done() and .fail() for new jQuery AJAX code instead of success and error
沒有留言:
張貼留言