解决node.js的req.body为空的问题

发布于:2024-12-18 ⋅ 阅读:(33) ⋅ 点赞:(0)

从昨晚一直在试,明明之前用的封装的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', //请求后端接口的baseUrl
    timeout: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-Type
    const 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博客


网站公告

今日签到

点亮在社区的每一天
去签到