首页 > 解决方案 > Angular 到 Node + Express.js http.post() 停止:状态 204 无内容。疑似 CORS 预检选项

问题描述

我正在使用客户端 ionic 和服务器端 node.js + express.js。目前在我的本地计算机上进行测试。

我可以通过邮递员发出 POST 请求,但是我无法通过 ionic 发出请求。

研究

我花了将近1天的时间来调查这个。但我找不到解决这个问题的方法。此外,客户端和服务器端都没有错误,因此我很难对此进行调查。

据我所见,我怀疑错误来自 PREFLIGHT OPTIONS 设置。我应该将它设置在我的节点 + 快递中的某个地方。我正在使用 cors 插件https://www.npmjs.com/package/cors并使用设置来允许 PREFLIGHT OPTIONS,但它仍然无法正常工作。

我查看了 chrome 网络检查,这就是我所拥有的: 网络巡检 (1) 网络巡检 (2)

这就是它在控制台中的样子。 控制台检查

我的客户端代码(离子)

postAPI() {
  return new Promise ((resolve,reject)=>{
    this.http.post("http://localhost:8080/api/status/", {
      "body" : "This is the body post"
    }, httpOptions).subscribe((val) => {
      console.log("POST call successful value returned in body", val);
      resolve();
    }, error => {
      console.log("POST call in error", error);
      reject();
    }, () => {
      console.log("The POST observable is now completed.");
    })
  })
}

我的服务器端代码(Node + Express)

在这里,我使用 CORS OPTIONS 设置来允许所有 OPTIONS 请求。我在 server.js 中设置它,而路由本身在 status.js 中。

服务器.js

const express    = require('express');           // call express
const app        = express();                    // define our app using express
var cors         = require('cors');               // setup CORS so can be called by ionic local app
const port       = process.env.PORT || 8080;      // set our port

// ALLOW CORS
app.use(cors());
// SET CORS for PREFLIGHT OPTIONS
app.options('*', cors());

// Libraries
const bodyParser = require('body-parser');

const admin   = require('firebase-admin');
const serviceAccount = require('./serviceAccountKey.json');

// Json
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());

// Firebase Configs
//firebase admin sdk for Firestore
admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
  databaseURL: "https://menuu-sm-dev.firebaseio.com"
});

var afs = admin.firestore();
var db = afs;
app.set("afs", afs);
var db = admin.firestore();
const settings = {timestampsInSnapshots: true};
db.settings(settings);

app.set("db", db);

// ROUTES
app.use('/api',require('./routers/api/api'));
app.use('/',require('./routers/home'));

// START
app.listen(port);
console.log('Server is served on port ' + port);

api.js

// SETUP
const express = require('express'),
  router = express.Router();
const url = require("url");
const path = require("path");
///const sanitizer = require("sanitize")();

// ROUTES (/api/)
router.use('/user',require('./user'));
router.use('/status',require('./status'));
router.use('/timeline',require('./timeline'));
router.use('/photo',require('./photo'));
router.use('/like',require('./like'));
router.use('/comment',require('./comment'));
router.use('/checkin',require('./checkin'));
router.use('/promotion',require('./promotion'));

// OTHERS
module.exports = router;

状态.js

// SETUP
const express = require('express'),
  router = express.Router();
const url = require("url");
const path = require("path");
const Timeline = require("../../models/Timeline");
const Post = require("../../models/Post");
///const sanitizer = require("sanitize")();

// ROUTES

// ===============================================================
// /status/
var statusRoute = router.route('');

// Create
statusRoute.post((req, res) => {
  let query = url.parse(req.url,true).query;
  let userKey = query.userkey;
  let statusKey = query.statuskey; // ga dipake
  let reqBody = req.body;
  let db = req.app.get('db');
  // ! remember to do sanitizing here later on

  if (typeof userKey != 'undefined'){
    // Create New Status
    let newStatusRef = db.collection('status/'+userKey+'/status').doc();
    newStatusRef.set(reqBody);

    // Fan-Out
    let docId = newStatusRef.id; // get pushed id
    //let docId = "1";

    // Insert request body to models
    var post = new Post();
    var timeline = new Timeline();
    Object.entries(reqBody).forEach( ([key, value]) => {
        timeline.set(key,value);
        post.set(key,value);
      }
    );

    // Specify operations to be done
    var batch = db.batch();
    let newPostRef = db.collection('posts/'+userKey+'/posts').doc(docId);
    batch.set(newPostRef, post.data);
    console.log("b" + batch);


    // Timeline & Commit
    getFollowers(userKey, db)
      .catch((error) => {
        console.error("Error writing document: ", error)
      })
      .then((followers) => {
        // ATTENTION!!
        // if followers > 9, batch write supposedly wont work because max limit of batch write is 10
        if (followers.length!=0){
          followers.forEach((f) => {
            let newTimelineRef = db.collection('timeline/'+String(f)+'/timeline').doc(docId);
            console.log(typeof batch);
            console.log("a" + batch);
            batch.set(newTimelineRef, timeline.data);
          });
        }

        // Commit changes
        batch.commit()
          .then(() => {
            console.log("POST Request");
            res.json({"Action":"CREATE","Status":"Successful", "User key":userKey, "Post Key": docId, "followers":followers});
          })
          .catch((error) => {
            console.error("Error writing document: ", error)
          })
      });
  }
});

你能帮我找出这个问题的原因吗?谢谢!

标签: node.jsangularexpressionic-frameworkcors

解决方案


将 app.use('cors') 替换为以下代码:

app.use((req, res, next) => {
  res.header("Access-Control-Allow-Origin", '*');
  res.header(
    "Access-Control-Allow-Headers",
    "Origin, X-Requested-With, Content-Type, Accept, Authorization"
  );
  if (req.method === 'OPTIONS') {
      res.header('Access-Control-Allow-Methods', 'PUT, POST, PATCH, DELETE, GET');
      return res.status(200).json({});
  }
  next();
});

推荐阅读