場景很簡單,就是一個正常 axios post 請求:java
axios({ headers: { 'deviceCode': 'A95ZEF1-47B5-AC90BF3' }, method: 'post', url: '/api/lockServer/search', data: { username, pwd } })
這就有點奇怪了,我看了一下瀏覽器的請求信息是 OK 的,參數都是有的,並且以前這樣用 axios 也沒有這個問題。ios
可是這個接口是通用的,別人都用了,是 OK 的,接口沒問題。git
緣由就是此次的接口使用 java spring mvc
而且在這個方法上使用了註解 @RequestParamspring
那麼這個是什麼意思呢,這個是隻能從請求的地址中取出參數,也就是隻能從 username=admin&password=admin這種字符串中解析出參數。json
咱們還能夠看到咱們此次請求的 Content-Type:axios
application/json;charset=UTF-8
==咱們知道在作 post 請求的時候,咱們的傳參是 data: {...} 或者直接 {...} 的形式傳遞的,嗯,就是下面這兩種形式==後端
==很是的刺激,這兩種形式無一例外都觸發了 axios 源碼中【很關鍵】的那一段代碼==api
也就是說,咱們的 Content-Type 變成了 application/json;charset=utf-8
而後,由於咱們的參數是 JSON 對象,axios 幫咱們作了一個 stringify 的處理。
並且查閱 axios 文檔能夠知道:axios 使用 post 發送數據時,默認是直接把 json 放到請求體中提交到後端的。瀏覽器
那麼,這就與咱們服務端要求的 'Content-Type': 'application/x-www-form-urlencoded' 以及 @RequestParam 不符合。mvc
【用 URLSearchParams 傳遞參數】
let param = new URLSearchParams() param.append('username', 'admin') param.append('pwd', 'admin') axios({ method: 'post', url: '/api/lockServer/search', data: param })
須要注意的是: URLSearchParams 不支持全部的瀏覽器,可是整體的支持狀況仍是 OK 的,因此優先推薦這種簡單直接的解決方案
網上有不少方案說使用
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
或者
{headers:{'Content-Type':'application/x-www-form-urlencoded'}}
我試了一下,其實這樣仍是不行的
【還須要額外的操做,(咱們要將參數轉換爲query參數)】
引入 qs ,這個庫是 axios 裏面包含的,不須要再下載了。
import Qs from 'qs' let data = { "username": "admin", "pwd": "admin" } axios({ headers: { 'deviceCode': 'A95ZEF1-47B5-AC90BF3' }, method: 'post', url: '/api/lockServer/search', data: Qs.stringify(data) })
既然 axios 源碼中有那麼一段【很關鍵】的代碼,那麼,咱們也能夠經過修改 transformRequest 來達到咱們的目的。
在 axios 的請求配置項中,是有 transformRequest 的配置的:
OK,那麼如今咱們的請求就能夠寫成下面這個樣子了:
import Qs from 'qs' axios({ url: '/api/lockServer/search', method: 'post', transformRequest: [function (data) { // 對 data 進行任意轉換處理 return Qs.stringify(data) }], headers: { 'deviceCode': 'A95ZEF1-47B5-AC90BF3' }, data: { username: 'admin', pwd: 'admin' } })
【重寫一個 axios 實例,從新實現屬於咱們本身的 transformRequest】
import axios from 'axios' let instance = axios.create({ transformRequest: [function transformRequest(data, headers) { normalizeHeaderName(headers, 'Content-Type'); if (utils.isFormData(data) || utils.isArrayBuffer(data) || utils.isBuffer(data) || utils.isStream(data) || utils.isFile(data) || utils.isBlob(data) ) { return data; } if (utils.isArrayBufferView(data)) { return data.buffer; } if (utils.isURLSearchParams(data)) { setContentTypeIfUnset(headers, 'application/x-www-form-urlencoded;charset=utf-8'); return data.toString(); } /*改了這裏*/ if (utils.isObject(data)) { setContentTypeIfUnset(headers, 'application/x-www-form-urlencoded;charset=utf-8'); let _data = Object.keys(data) return encodeURI(_data.map(name => `${name}=${data[name]}`).join('&')); } return data; }], })
axios.post('/api/lockServer/search',"userName='admin'&pwd='admin'");
咱們知道如今咱們服務端同窗接收參數用的是 @RequestParam(經過字符串中解析出參數)
其實還有另外一種是 @RequestBody(從請求體中獲取參數)。
咱們讓後端的同窗改爲 @RequestBody 不就能夠了嗎
@RequestMapping(value = "h5/delSelSignalSourceByAccount", method = RequestMethod.POST) @ResponseBody public JsonResult delSelSignalSourceByAccount(@RequestBody String json) { JSONObject jsonObject= JSON.parseObject(json); String operateAccount=jsonObject.getString("operateAccount"); JSONArray positiveAccounts=jsonObject.getJSONArray("positiveAccounts"); JSONArray nagitiveAccounts=jsonObject.getJSONArray("nagitiveAccounts"); List<String> posiAccounts = null; List<String> nagiAccounts = null; if (positiveAccounts != null) { posiAccounts = JSONObject.parseArray(positiveAccounts.toJSONString(),String.class); } if (nagitiveAccounts != null) { nagiAccounts = JSONObject.parseArray(nagitiveAccounts.toJSONString(),String.class); } eaQuanXianService.delSelSignalSourceByAccount(operateAccount, posiAccounts, nagiAccounts); return new JsonResult(); }