1. 程式人生 > >Vue中axios 表單POST提交

Vue中axios 表單POST提交

剛開始使用Vue,裡面的坑是一個接一個,今天就遇到一個axios POST傳參的問題。

因為後端要求是按表單提交的形式給他資料,

我需要在請求中傳遞引數,然後按官方文件的格式開始操作,程式碼如下:

axios.post('/user', {

    firstName: 'Fred',

    lastName: 'Flintstone'

  })

  .then(function (response) {

    console.log(response);

  })

  .catch(function (error) {

    console.log(error);

  });

注:此處是官方示例:點選開啟連結

 

開啟控制檯,報400,報錯資訊是:傳遞的引數不存在,但在請求中看的到引數,只是引數的格式是Request Payload,具體也沒看懂是什麼,總之知道就是引數格式不對,查閱資料找到兩種解決辦法,程式碼如下:

1.es6寫法

import qs from 'qs';
const data = { 'bar': 123 };
const options = {
  method: 'POST',
  headers: { 'content-type': 'application/x-www-form-urlencoded' },
  data: qs.stringify(data),
  url,
};
axios(options);

2.

var params = new URLSearchParams();
params.append('param1', 'value1');
params.append('param2', 'value2');
axios.post('/foo', params);

參考:https://github.com/axios/axios#using-applicationx-www-form-urlencoded-format

經測試,這兩種辦法都可以

這個問題剛解決,後臺就拋給我一個問題,我的引數裡面要傳陣列呢,我以為直接按上面的做法就能一馬平川了,然而現實是殘酷的,崩盤!檢視官方文件發現,其實這個的解決也是非常的簡單,只需要在qs的方法中設定它的indices為false即可,如:

qs.stringify({ a: ['b', 'c', 'd'] }, { indices: false });

更多qs功能參考:https://www.npmjs.com/package/qs

 

 

 

 

 

 

 

 

vue框架推薦使用axios來發送ajax請求,之前我還寫過一篇部落格來講解如何在vue元件中使用axios。但之前做著玩用的都是get請求,現在我自己搭部落格時使用了post方法,結果發現後臺(node.js)完全拿不到前臺傳來的引數。後來進過一番探索,終於發現問題所在。

post提交資料的四種編碼方式
1.application/x-www-form-urlencoded 
這應該是最常見的post編碼方式,一般的表單提交預設以此方式提交。大部分伺服器語言對這種方式都有很好的支援。在PHP中,可以用$_POST[“key”]的方式獲取到key的值,在node中我們可以使用querystring中介軟體對引數進行分離

app.post("/server",function(req,res){
    req.on("data",function(data){
        let key=querystring.parse(decodeURIComponent(data)).key;
        console.log("querystring:"+key)
    });
});



2.multipart/form-data 
這也是一種比較常見的post資料格式,我們用表單上傳檔案時,必須使form表單的enctype屬性或者ajax的contentType引數等於multipart/form-data。使用這種編碼格式時傳送到後臺的資料長得像這樣子 
 
不同欄位以--boundary開始,接著是內容描述資訊,最後是欄位具體內容。如果傳輸的是檔案,還要包含檔名和檔案型別資訊

3.application/json 
axios預設提交就是使用這種格式。如果使用這種編碼方式,那麼傳遞到後臺的將是序列化後的json字串。我們可以將application/json與application/x-www-form-urlencoded傳送的資料進行比較 
首先是application/json: 
 
接著是application/x-www-form-urlencoded: 
 
這裡可以明顯看出application/x-www-form-urlencoded上傳到後臺的資料是以key-value形式進行組織的,而application/json則直接是個json字串。如果在處理application/json時後臺還是採用對付application/x-www-form-urlencoded的方式將會產生問題。例如後臺node.js依然採用之前對付application/x-www-form-urlencoded的方法,那麼querystring.parse(decodeURIComponent(data))之後得到的資料是這樣子的 
 
這個時候再querystring.parse(decodeURIComponent(data)).key只能獲取到undefined

4.text/xml 
剩下的一種編碼格式是text/xml,這種格式我沒有怎麼使用過

解決方法
既然我們知道axios post方法預設使用application/json格式編碼資料,那麼解決方案就有兩種,一是後臺改變接收引數的方法,另一種則是將axios post方法的編碼格式修改為application/x-www-form-urlencoded,這樣就不需要後臺做什麼修改了。 
先來看第一種解決方法 
vue元件中,axios傳送post請求的程式碼如下

this.$axios({
    method:"post",
    url:"/api/haveUser",
    data:{
        name:this.name,
        password:this.password
    }
}).then((res)=>{
    console.log(res.data);
})



此時控制檯Network Headers裡面的資訊是這樣子的 
 
後臺接收資料需要依賴body-parser中介軟體,我們事先裝好,接著在後臺程式碼中引用body-parser 
 
這張截圖中,發揮作用的程式碼僅僅是const bodyParser=require("body-parser"); 
接下來在路由中使用body-parser

app.post("/api/haveUser",bodyParser.json(),function(req,res){
    console.log(req.body);
    let haveUser=require("../api/server/user.js");
    haveUser(req.body.name,req.body.password,res);
});



這時,當前臺傳送post請求之後,後臺控制檯中就會打印出req.body 
 
這時,通過req.body.name或者req.body.password就能拿到對應的值。 
這種方法比較簡單,也不需要前臺做過多修改,推薦使用這種方法。

第二種解決方法,具體操作如下 
前端

this.$axios({
    method:"post",
    url:"/api/haveUser",
    headers:{
        'Content-type': 'application/x-www-form-urlencoded'
    },
    data:{
        name:this.name,
        password:this.password
    },
    transformRequest: [function (data) {
        let ret = ''
        for (let it in data) {
          ret += encodeURIComponent(it) + '=' + encodeURIComponent(data[it]) + '&'
        }
        return ret
      }],
}).then((res)=>{
    console.log(res.data);
})



其中發揮關鍵作用的是headers與transformRequest。其中 headers 是設定即將被髮送的自定義請求頭。 transformRequest 允許在向伺服器傳送前,修改請求資料。這樣操作之後,後臺querystring.parse(decodeURIComponent(data))獲取到的就是類似於{ name: 'w', password: 'w' }的物件。後臺程式碼如下

app.post("/api/haveUser",function(req,res){
      let haveUser=require("../api/server/user.js");
      req.on("data",function(data){
          let name=querystring.parse(decodeURIComponent(data)).name;
          let password=querystring.parse(decodeURIComponent(data)).password;
          console.log(name,password)
          haveUser(name,password,res);
      });
});



這種方法明顯就要比第一種麻煩一點,但不需要後臺做過多處理。所以具體操作還是得根據實際情況決定。