อนุญาตคำขอ CORS REST ไปยังแอปพลิเคชัน Express / Node.js บน Heroku


98

ฉันได้เขียน REST API บนเฟรมเวิร์กด่วนสำหรับ node.js ที่ใช้กับคำขอจากคอนโซล js ใน Chrome และแถบ URL ฯลฯ ตอนนี้ฉันกำลังพยายามทำให้มันทำงานกับคำขอจากแอปอื่น โดเมน (CORS)

คำขอแรกที่สร้างขึ้นโดยอัตโนมัติโดยส่วนหน้าของจาวาสคริปต์คือการ / api / search? uri = และดูเหมือนจะล้มเหลวในคำขอ OPTIONS "preflight"

ในแอปด่วนของฉันฉันกำลังเพิ่มส่วนหัว CORS โดยใช้:

var allowCrossDomain = function(req, res, next) {
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
    res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With');

    // intercept OPTIONS method
    if ('OPTIONS' == req.method) {
      res.send(200);
    }
    else {
      next();
    }
};

และ:

app.configure(function () {
  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(app.router);
  app.use(allowCrossDomain);
  app.use(express.static(path.join(application_root, "public")));
  app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});

จากคอนโซล Chrome ฉันได้รับส่วนหัวเหล่านี้:

ขอ URL: http: //furious-night-5419.herokuapp.com/api/search? uri = http% 3A% 2F% 2Flocalhost% 3A5000% 2Fcollections% 2F1% 2Fdocuments% 2F1

วิธีการขอ: OPTIONS

รหัสสถานะ: 200 ตกลง

ขอส่วนหัว

Accept:*/*
Accept-Charset:ISO-8859-1,utf-8;q=0.7,*;q=0.3
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Access-Control-Request-Headers:origin, x-annotator-auth-token, accept
Access-Control-Request-Method:GET
Connection:keep-alive
Host:furious-night-5419.herokuapp.com
Origin:http://localhost:5000
Referer:http://localhost:5000/collections/1/documents/1
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_4) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.56 Safari/536.5

พารามิเตอร์สตริงการสืบค้น

uri:http://localhost:5000/collections/1/documents/1

ส่วนหัวการตอบกลับ

Allow:GET
Connection:keep-alive
Content-Length:3
Content-Type:text/html; charset=utf-8
X-Powered-By:Express

ดูเหมือนว่าแอปพลิเคชัน API จะส่งส่วนหัวที่ไม่ถูกต้องหรือไม่

ขอบคุณ.


ฉันได้รับข้อผิดพลาดนี้ในรหัสที่ฉันไม่ได้เขียน แต่ฉันไม่เข้าใจความจำเป็นของตัวจัดการสำหรับOPTIONSวิธีการนี้ ใครช่วยกรุณาช่วยให้ฉันเข้าใจว่าทำไมไม่จัดการเพียงPOSTวิธีการแทนที่จะจัดการทั้งสองPOST และ OPTIONSวิธีการ
Ulysses Alves

อาจต้องการรวมไว้ด้วยPATCHหากคุณจะใช้แทนPUTการอัปเดตทรัพยากร
Danny

คำตอบ:


66

ฉันได้ตรวจสอบรหัสของคุณในแอป ExpressJS ที่สะอาดและใช้งานได้ดี

ลองย้ายapp.use(allowCrossDomain)ไปที่ด้านบนสุดของฟังก์ชันกำหนดค่า


8
เหตุผลที่เป็นเพราะคุณต้องกำหนดไว้ก่อนapp.use(app.router);Cheers!
คาล

ในกรณีของฉัน POST ถัดไปจะไม่ถูกเรียกหลังจากส่ง res.send (200) กลับเมื่อ req.method == 'OPTIONS' ฉันขาดอะไรไปอีกไหม?
Aldo

2ldo: รหัสที่จำเป็น คุณอาจลืมบางส่วนหัว? หากไคลเอนต์ของคุณไม่ได้ส่ง POST หลังจากที่เซิร์ฟเวอร์ของคุณได้รับคำขอตัวเลือกการสั่งซื้อล่วงหน้าอย่างถูกต้องให้ลองตรวจสอบคอนโซลเครื่องมือสำหรับนักพัฒนา WebKit บันทึกข้อผิดพลาดประเภทนี้ไปยังคอนโซลของผู้ตรวจสอบเว็บ
Olegas

1
@ConnorLeech น่าร้ากกก ฉันใช้วิธี allowCrossDomain ข้างต้นและเบื่อที่จะจัดการกับส่วนหัวทั้งหมดนั้น นอกจากนี้ - เนื่องจากเราต้องการเพียง CORS สำหรับนักพัฒนาเท่านั้นจึงไม่สมเหตุสมผลเลยที่จะอุทิศรอบมากมายเพื่อค้นหาว่าเกิดอะไรขึ้น ดีใจที่มีการสนับสนุน node.js เพื่อให้อนุญาตสิ่งนี้ได้อย่างง่ายดาย
Steven

1
@ConnorLeech ฉันคิดว่าคุณควรเพิ่มความคิดเห็นของคุณเป็นคำตอบ ... ใช้งานได้ดีและดีและเรียบง่าย
drmrbrewer

4

สำหรับการสนับสนุนคุกกี้ด้วยข้อมูลประจำตัวคุณต้องใช้บรรทัดนี้ xhr.withCredentials = true;

mdn docs xhr. withCredentials

ใน Express Server ให้เพิ่มบล็อกนี้ก่อนบล็อกอื่น ๆ

`app.all('*', function(req, res, next) {
     var origin = req.get('origin'); 
     res.header('Access-Control-Allow-Origin', origin);
     res.header("Access-Control-Allow-Headers", "X-Requested-With");
     res.header('Access-Control-Allow-Headers', 'Content-Type');
     next();
});`

4

ฉันกำลังเพิ่มสิ่งนี้เป็นคำตอบเท่านั้นเนื่องจากโพสต์ต้นฉบับถูกใส่ไว้ในความคิดเห็นและทำให้คุณมองข้ามไปในครั้งแรกที่ฉันอ่านหน้านี้

ดังที่ @ConnorLeech ชี้ให้เห็นในความคิดเห็นของเขาต่อคำตอบที่ยอมรับข้างต้นมีแพ็คเกจ npm ที่มีประโยชน์มากเรียกว่าcorsไม่น่าแปลกใจเลย ใช้มันเป็นง่ายๆเป็นvar cors = require('cors'); app.use(cors());(อีกครั้ง cribbed จากคำตอบของนายปลิง) และนอกจากนี้ยังสามารถนำไปใช้ในที่เข้มงวดเป็นแฟชั่นที่กำหนดมากขึ้นตามที่ระบุไว้ในของพวกเขาเอกสาร

นอกจากนี้ยังอาจคุ้มค่าที่จะชี้ให้เห็นว่าความคิดเห็นดั้งเดิมที่ฉันอ้างถึงข้างต้นนั้นสร้างขึ้นในปี 2014 ตอนนี้เป็นปี 2019 และดูที่หน้า github ของแพ็คเกจ npmที่ repo ได้รับการอัปเดตเมื่อเร็ว ๆ นี้เมื่อเก้าวันที่แล้ว


0

มันไม่อาจเป็นกรณีสำหรับคนส่วนใหญ่เรียกดูคำถามนี้ CORSแต่ฉันมีปัญหาเดียวกันนี้แน่นอนและวิธีการแก้ปัญหาที่ไม่ได้เกี่ยวข้องกับการ

ปรากฎว่าความลับของ JSON Web Token stringไม่ได้กำหนดไว้ในตัวแปรสภาพแวดล้อมดังนั้นจึงไม่สามารถเซ็นโทเค็นได้ สิ่งนี้เกิดจากPOSTคำขอใด ๆที่อาศัยการตรวจสอบหรือการลงนามโทเค็นเพื่อให้หมดเวลาและส่งคืน503ข้อผิดพลาดโดยแจ้งให้เบราว์เซอร์ทราบว่ามีบางอย่างผิดปกติCORSซึ่งไม่ใช่ การเพิ่มตัวแปรสภาพแวดล้อมใน Heroku ช่วยแก้ปัญหาได้

ฉันหวังว่านี่จะช่วยใครบางคนได้


ใช่นั่นเป็นปัญหากับฉัน คุณสามารถระบุวิธีแก้ปัญหาได้ชัดเจนขึ้น ฉันยังอยู่ในระหว่างการพัฒนาและกำลังรันบนแพ็คเกจ Express.js w / node cors
Alan

@ ลันฉันใช้คำสัญญาในการยืนยันโทเค็นในแอปพลิเคชันของฉันบางอย่างหากไม่ได้กำหนดความลับ JWT คำสัญญาจะไม่มีวันแก้ไขได้นี่คือรหัสที่ฉันใช้หากคุณต้องการข้อมูลอ้างอิงเพิ่มเติม
CatBrownie

ขอบคุณสำหรับการตอบกลับ ฉันจะดูรหัส โดยความลับฉันถือว่าคุณกำลังพูดถึงคีย์ส่วนตัวที่สอง ฉันใช้ oauth2
Alan

ฉันจะเพิ่มว่าสัญญาที่ล้มเหลวใด ๆ จะทำให้เกิดข้อผิดพลาดที่ทำให้เข้าใจผิดนี้! ฉันต้องมีความชัดเจนเกี่ยวกับเวอร์ชันโหนดที่ใช้ไม่เช่นนั้นการเรียกฐานข้อมูลของฉัน (mongo) ก็ห้อยอยู่และสิ่งเดียวที่เบราว์เซอร์สามารถบอกฉันได้คือ 503 และจากนั้นก็มีความโง่เขลาที่เกี่ยวข้องกับ Cors ข้อผิดพลาดนี้ทำให้ฉันสับสนมากที่สุดเท่าที่ฉันเคยapp.use(cors());ทำมา
alphanumeric0101

0

ป้อนคำอธิบายภาพที่นี่

ทำตามขั้นตอนด้านล่าง:

npm ติดตั้ง cors - บันทึก

ภายในไฟล์ root js ของคุณ:

 var express = require('express') 
 var cors = require('cors')
 var app = express()
 app.use(cors())
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.