從昨晚一直在試,明明之前用的封裝的axios發送請求給其他的后端(springboot)是可以的,但昨天用了新項目的后端(node.js)就不行。
之前用了代理,所以瀏覽器發送的post請求不會被攔截,但是昨天因為項目的接口沒有統一前綴的原因(比如都用admin)開頭,所以直接把baseUrl寫成http://127.0.0.1:7123了,但是發送post請求出錯,我還以為前端寫錯了,后面發現post請求的話總不行,報是跨域的問題,但是get的話就可以,查了一下,get的話請求參數會被放在query里面,post請求會跨域,所以node那邊得寫成? res.header("Access-Control-Allow-Headers", "X-Requested-With,Content-Type");原來的話是?res.header("Access-Control-Allow-Headers", "X-Requested-With")
解決跨域問題的寫法:(記得加Content-Type)
res.header("Access-Control-Allow-Headers", "X-Requested-With,Content-Type");
總結,如果post用application/x-www-form-urlencoded,得格式化數據
// 2. 使用 URLSearchParams 格式化數據const formData = new URLSearchParams();for (const key in data1) {formData.append(key, data1[key]);}// 3. 發送 POST 請求axios.post('http://127.0.0.1:7123/admin/login', formData, {headers: {'Content-Type': 'application/x-www-form-urlencoded',},})
如果post用json,則不用,因為axios會自動幫我們json化
const data1 = {account: 'value1',password: 'value2'};// 2. 使用 URLSearchParams 格式化數據const formData = new URLSearchParams();for (const key in data1) {formData.append(key, data1[key]);}// 3. 發送 POST 請求axios.post('http://127.0.0.1:7123/admin/login', data1, {headers: {'Content-Type': 'application/json',},})
上面的例子是不封裝的情況,如果是封裝的話,如果傳進來dataType:"json"格式,按照以下代碼可以執行,因為這時候Content-Type為application/json,后端用req.body可以獲取到
import axios from "axios"
import { ElLoading } from 'element-plus'; // 正確的拼寫是 ElLoading,不是 Lloading
import router from '@/router'
import Message from '../utils/Message'
import { getCurrentInstance } from "vue";
const contentTypeForm='application/x-www-form-urlencoded;charset-UTF-8'
const contentTypeJson='application/json'
const contentTypeMulti ='multipart/form-data'
let loading=null;
import VueCookies from 'vue-cookies';
const instance=axios.create({baseURL:'http://127.0.0.1:7123', //請求后端接口的baseUrltimeout:10*1000, //設置請求的超時時間
})
//請求前攔截器
instance.interceptors.request.use((config)=>{const data= VueCookies.get("loginInfo");if(data){const token=data.token;if (token) {config.headers.token = token}}if(config.showLoading){loading=ElLoading.service({lock:true,text:'加載中……',background:'rgba(0,0,0,0.7)',})}return config;},(error)=>{if(config.showLoading&&loading){loading.close();}Message.error("請求發送失敗");return Promise.reject("請求發送失敗");}
);
//請求后攔截器
instance.interceptors.response.use((response)=>{const{showLoading,errorCallback,showError=true}=response.config;if(showLoading&&loading){loading.close();}//正常請求if (response.status==200){return response.data;}},(error)=>{const { showLoading, errorCallback, showError = true } = error.config;if (showLoading && loading) {loading.close();}(error.response);if(error.response){const responseData = error.response;if (responseData.status == 401) {setTimeout(() => {router.push("/login")}, 2000);return Promise.reject({ showError: true, msg: "登錄超時" });}}if(error.config.showLoading&&loading){loading.close();}return Promise.reject({showError:true,msg:"網絡異常"})}
);
const request = ({ url, method, params, dataType, showLoading = true, errorCallback, showError = true, data }) => {// 設置默認 Content-Typeconst contentType = method === 'upload' ? contentTypeMulti : (dataType === 'json' ? contentTypeJson : contentTypeForm);// 處理請求數據const requestData = method === 'upload' ? { data } : (method === 'get' || method === 'delete' ? { params } : { data: params });// 上傳請求強制使用 POST 方法if (method === 'upload') {method = 'post';}return instance.request({method,url,...requestData,headers: {'Content-Type': contentType,'X-Requested-With': 'XMLHttpRequest',},showLoading,}).catch(error => {console.error(error);if (showError) {Message.error(error.msg || 'An error occurred');}if (errorCallback) {errorCallback(error);}return null;});
};export default request;
但是如果不傳入dataType的話,默認為application/x-www-form-urlencoded的話,就要注意了,
?const requestData = method === 'upload' ? { data } : (method === 'get' || method === 'delete' ? { params } : { data: params });這行代碼得改為?const requestData = method === 'upload' ? { data } : (method === 'get' || method === 'delete' ? { params } : { params });因為application/x-www-form-urlencoded是以 類似‘name=edward&age=25’? 這樣的形式放在參數中,后端得用req.query才能獲取數據,req.body獲取不到。
但是如果要在req.body獲取得到的話,那么
import qs from 'qs';const request = axios.create({baseURL: process.env.BASE_URL,headers: {'Content-Type': 'application/x-www-form-urlencoded',}
})request.interceptors.request.use(config => {if (config.method === 'post') {config.data = qs.stringify(config.data)}return config;
})
記得要qs序列化。!!!!!!!!!!!!!!!!!!!!!!!!!
暫時先寫這么多,后續有更清晰的理解再補充,哪里寫錯還請路過的大佬斧正。
貼一下原貼
post請求頭設置成application/json時的跨域錯誤_指定contenttype為json后報跨域-CSDN博客