form表單提交、ajax、fetch、formdata,以及跨域

一.form表單提交

1.1 簡單的介紹

<!-- form 表單post提交,默認會刷新到 action 頁面 -->
    <form action="www.baidu.com" method="POST" name="post提交">
      <p>name: <input type="text" name="username"></p>
      <p>password: <input type="password" name="password"></p>
      <input type="submit" value="提交">
    </form>
    
<!-- form 表單get 提交, 默認刷新action 頁面 -->
    <form action="www.baidu.com" method="GET" name="get提交">
      <p>name: <input type="text" name="username"></p>
      <p>password: <input type="password" name="password"></p>
      <input type="submit" value="提交">
    </form>

  • form 的提交行爲需要通過type=submit實現

  • form 中的method 屬性不指定時, form 默認的提交方式爲 get請求。

  • 表單提交時表單內容會被瀏覽器封裝爲HTTP請求報,裏面包含了所有表單元素的name屬性值和value屬性的值,形式爲name=value。

  • form 表單的提交後會有默認行爲,會跳轉刷新到action 的頁面

  • 當一個form 表單內部,所有的input 中只有一個 type=‘text’ 的時候,enter 鍵會有默認的提交行爲(注意前提條件)

  • 組織默認行爲可以在submit事件時retur false

1.2 編碼方式提交表單數據

<form>標籤的屬性enctype設置以何種編碼方式提交表單數據。可選的值有三個:
1.這是默認的編碼方式。它只處理表單域裏的value屬性值,採用這種變法方式的表單會將表單域的值處理成URL方式。

   application/x-www-form-urlencoded:

2.這種編碼方式會以二進制流的方式來處理表單數據,這中編碼方式會把文件域指定的文件內容也封裝到請求參數裏。

  multipart/form-data: 

不用後臺接受這樣的數據,需要注意,接受的可能是:

------WebKitFormBoundaryQqpAxgR2Pgik6uyY

      Content-Disposition: form-data; name="f"; filename="hello.txt"

      Content-Type: application/octet-stream

這時需要處理,例如node可以採用formidabled或者multiparty插件處理

3.這種方式當表單的action屬性值爲mailto:URL的形式時比較方便,這種方式主要適用於直接通過表單發送郵件。

   text/plain:

1.3 form表單爲何沒有跨域限制

跨域問題只是瀏覽器強加給js的規則。瀏覽器強制不允許js訪問別的域,但是瀏覽器卻沒有限制它自己。比如說img標籤可以加載任何域的圖片,script可以加載任何域的js。

form 提交是瀏覽器行爲,提交到另一個域名之後,原頁面的腳本無法獲取新頁面中的內容。所以瀏覽器認爲這是安全的。

而 AJAX 是可以讀取響應內容的,因此瀏覽器不能允許你這樣做。如果你細心的話你會發現,其實請求已經發送出去了,你只是拿不到響應而已。所以瀏覽器這個策略的本質是,一個域名的 JS ,在未經允許的情況下,不得讀取另一個域名的內容。但瀏覽器並不阻止你向另一個域名發送請求。

二.ajax

JavaScript執行異步網絡請求。
如果仔細觀察一個Form的提交,你就會發現,一旦用戶點擊“Submit”按鈕,表單開始提交,瀏覽器就會刷新頁面,然後在新頁面裏告訴你操作是成功了還是失敗了。如果不幸由於網絡太慢或者其他原因,就會得到一個404頁面。

這就是Web的運作原理:一次HTTP請求對應一個頁面。

如果要讓用戶留在當前頁面中,同時發出新的HTTP請求,就必須用JavaScript發送這個新請求,接收到數據後,再用JavaScript更新頁面,這樣一來,用戶就感覺自己仍然停留在當前頁面,但是數據卻可以不斷地更新。

在現代瀏覽器上寫AJAX主要依靠XMLHttpRequest對象:

var xhr=new XMLHttpRequest();

xhr.open("GET","ajax_info.txt",true);
xhr.send();
xhr.onreadystatechange=function (){
   if(xhr.readyState==4){
     if(xhr.status>=200 && xhr.status<300 || xhr.status==304){
       alert('成功');
       let json=JSON.parse(xhr.responseText);
       console.log(json);
     }else{
       alert('失敗');
     }
   }
};
屬性 描述
open(method,url,async) 規定請求的類型、URL 以及是否異步處理請求。 method:請求的類型;GET 或 POSTurl:文件在服務器上的位置async:true(異步)或 false(同步)
send(string) 將請求發送到服務器。string:僅用於 POST 請求
onreadystatechange 存儲函數(或函數名),每當 readyState 屬性改變時,就會調用該函數。
readyState 存有 XMLHttpRequest 的狀態。從 0 到 4 發生變化。0: 請求未初始化1: 服務器連接已建立2: 請求已接收3: 請求處理中4: 請求已完成,且響應已就緒
responseText 獲得字符串形式的響應數據
status 200-300表示成功,304表示使用緩存

三. fatch

MDN介紹
如果遇到不支持fech的可以使用第三方的ployfill來實現只會fetch:whatwg-fetch
有一篇文章寫的很好,我這裏就不廢話了https://segmentfault.com/a/1190000011433064
這裏只幾個舉例子

可以使用async await
獲取文本

let oBtn=document.getElementById('btn1');
      oBtn.onclick=async function (){
        //1.請求
        let res=await fetch('data/1.txt');
        //2.解析
        let str=await res.text();

        alert(str);
      };

獲取json

window.onload=function (){
      let oBtn=document.getElementById('btn1');
      oBtn.onclick=async function (){
        //1.請求
        let res=await fetch('data/1.json');
        //2.解析
        let json=await res.json();
        console.log(json);
      };
    };

獲取圖片

window.onload=function (){
      let oImg=document.getElementById('img1');
      let oBtn=document.getElementById('btn1');
      oBtn.onclick=async function (){
        //1.請求
        let res=await fetch('data/1.png');
        //2.解析
        let data=await res.blob();
        let url=URL.createObjectURL(data);

        oImg.src=url;
      };
    };

.四fomdata

ajax2添加了一個新的接口FormData. 利用FormData對象,我們可以通過JavaScript用一些鍵值對來模擬一系列表單控件,我們還可以使用XMLHttpRequestsend()方法來異步的提交這個"表單".比起普通的ajax,使用FormData的最大優點就是我們可以異步上傳一個二進制文件.
直接來看例子:
基本使用:

<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title></title>
  </head>
  <body>
    <form id="form1" action="http://localhost:8080/" method="post">
      用戶:<input type="text" name="user" /><br>
      密碼:<input type="password" name="pass" /><br>
      文件:<input type="file" name="f1" /><br>
      <input type="submit" value="提交">
    </form>
  </body>
  <script>
  let oForm=document.querySelector('#form1');

  oForm.onsubmit=function (){
  	// new一個FormData實例
    let formdata=new FormData(oForm);
	// 這是ajax
    let xhr=new XMLHttpRequest();
    xhr.open(oForm.method, oForm.action, true);
    xhr.send(formdata);

    xhr.onreadystatechange=function (){
      if(xhr.readyState==4){
        if(xhr.status==200){
          alert('成功');
        }else{
          alert('失敗');
        }
      }
    };

    return false;
  };
  </script>
</html>

利用jq

<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title></title>
  </head>
  <body>
    <form id="form1" action="http://localhost:8080/" method="post">
      用戶:<input type="text" name="user" /><br>
      密碼:<input type="password" name="pass" /><br>
      文件:<input type="file" name="f1" /><br>
      <input type="submit" value="提交">
    </form>
  </body>
  <script src="jquery.js" charset="utf-8"></script>
  <script>
  $('#form1').on('submit', function (){
    let formdata=new FormData(this);

    $.ajax({
      url: this.action,
      type: this.method,
      data: formdata,
       //  
      processData: false,
      // FormData時jq會自動改變類型,我們不允許
      contentType: false
    }).then(res=>{
      alert('成功');
    }, res=>{
      alert('失敗');
    });

    return false;
  });
  </script>
</html>

不實用form表單

<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title></title>
  </head>
  <body>
    <div id="div1">
      用戶:<input type="text" id="user" /><br>
      密碼:<input type="password" id="pass" /><br>
      文件:<input type="file" id="f1" /><br>
      <input id="btn1" type="button" value="提交">
    </div>
  </body>
  <script>
  let oBtn=document.querySelector('#btn1');
  oBtn.onclick=function (){
    let formdata=new FormData();

    formdata.append('username', document.querySelector('#user').value);
    formdata.append('password', document.querySelector('#pass').value);
    formdata.append('f1', document.querySelector('#f1').files[0]);

    //
    let xhr=new XMLHttpRequest();

    xhr.open('post', 'http://localhost:8080/', true);
    xhr.send(formdata);

    xhr.onreadystatechange=function (){
      if(xhr.readyState==4){
        if(xhr.status==200){
          alert('成功');
        }else{
          alert('失敗');
        }
      }
    };
  };
  </script>
</html>

使用node接收數據
multiparty需要install

const http=require('http');
const multiparty=require('multiparty');

http.createServer((req, res)=>{
  let form=new multiparty.Form({uploadDir: './upload/'});

  form.parse(req);

  form.on('field', (name, value)=>{
    console.log('field:', name, value);
  });
  form.on('file', (name, file)=>{
    console.log('file:', name, file);
  });

  form.on('close', ()=>{
    console.log('完事');
  });
}).listen(8080);

四。在服務端設置跨域
我們以node作爲後端,直接來設置

const http=require('http');

// 我們允許訪問的地址
let allowOrigin={
  'http://localhost': true,
  'http://aaa.com': true,
  'https://aaa.com': true,
}

http.createServer((req, res)=>{
  let {origin}=req.headers;

  if(allowOrigin[origin]){
  	// 設置爲*表示允許任何地址訪問
    res.setHeader('access-control-allow-origin', '*');
  }

  res.write('{"a": 12, "b": "Blue"}');
  res.end();
}).listen(8080);

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章