คำขอส่วนหัวฟิลด์ Access-Control-Allow-Headers ไม่ได้รับอนุญาตด้วยตัวเองในการตอบสนอง preflight


234

ฉันเจอปัญหา CORS หลายครั้งและมักจะแก้ไขได้ แต่ฉันต้องการที่จะเข้าใจจริงๆโดยเห็นสิ่งนี้จากกระบวนทัศน์สแต็กหมายถึง

ก่อนที่ฉันจะเพิ่มมิดเดิลแวร์ในเซิร์ฟเวอร์ด่วนของฉันเพื่อจับสิ่งเหล่านี้ แต่ดูเหมือนว่ามีตะขอบางประเภทที่ผิดพลาดคำขอของฉัน

คำขอส่วนหัวฟิลด์ Access-Control-Allow-Headers ไม่ได้รับอนุญาตจาก Access-Control-Allow-Headers ในการตอบกลับ preflight

ฉันคิดว่าฉันสามารถทำได้:

app.use(function(req, res, next) {
  res.header("Access-Control-Allow-Headers","*")
})

หรือสิ่งที่เทียบเท่า แต่ดูเหมือนจะไม่สามารถแก้ไขได้ ฉันยังพยายามแน่นอน

app.use(function(req, res, next) {
  res.header("Access-Control-Allow-Headers","Access-Control-Allow-Headers")
})

ยังไม่มีโชค

คำตอบ:


245

เมื่อคุณเริ่มเล่นกับส่วนหัวคำขอที่กำหนดเองคุณจะได้รับ preflight CORS นี่คือคำขอที่ใช้OPTIONSกริยาHTTP และรวมหลายส่วนหัวโดยหนึ่งในนั้นกำลังแสดงAccess-Control-Request-Headersรายการส่วนหัวที่ไคลเอ็นต์ต้องการรวมไว้ในคำขอ

คุณต้องตอบกลับ preflight CORS นั้นด้วยส่วนหัว CORS ที่เหมาะสมเพื่อใช้งานนี้ Access-Control-Allow-Headersซึ่งหนึ่งในนั้นเป็นจริง ส่วนหัวนั้นต้องมีค่าเดียวกันกับAccess-Control-Request-Headersส่วนหัวที่มี (หรือมากกว่า)

https://fetch.spec.whatwg.org/#http-cors-protocolอธิบายการตั้งค่านี้ในรายละเอียดเพิ่มเติม


41
หากคุณใช้ Chrome และไม่แน่ใจว่ามีการร้องขอส่วนหัวใดให้ใช้คอนโซลนักพัฒนาระบบเครือข่ายเลือกการโทรและคุณสามารถดูว่าส่วนหัวใดที่ถูกร้องขอโดยAccess-Control-Request-Headers
Lionel Morrison

5
ตัวเลือก Developer Console นั้นดี นอกจากนี้คุณยังสามารถค้นหาสิ่งที่คุณต้องการโดยการเข้าถึงวัตถุคำขอบนเซิร์ฟเวอร์และทิ้งค่าสำหรับส่วนหัว แต่เฉพาะค่าส่วนหัวสำหรับ "Access-Control-Request-Headers" จากนั้นคัดลอก / วางสิ่งนี้ลงใน response.setHeader ของคุณ ("Access-Control-Allow-Headers", "{paste here}")
ผู้เผยพระวจนะซอฟต์แวร์

7
ตัวอย่างได้โปรด!
Demodave

5
@Demodave ตัวอย่างของสิ่งนี้สำหรับฉันคือheader("Access-Control-Allow-Headers: Content-Type")
Joshua Duxbury

1
@LionelMorrison ใช้เครื่องมือ chrome dev สำหรับส่วนหัวที่ตรงกัน อธิบายได้ดี !!!
Savina Chandla

119

นี่คือสิ่งที่คุณต้องเพิ่มเพื่อให้ทำงานได้

response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "GET,HEAD,OPTIONS,POST,PUT");
response.setHeader("Access-Control-Allow-Headers", "Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers");

เบราว์เซอร์ส่งคำขอ preflight (พร้อมตัวเลือกประเภทวิธี) เพื่อตรวจสอบว่าบริการที่โฮสต์บนเซิร์ฟเวอร์ได้รับอนุญาตให้เข้าถึงจากเบราว์เซอร์ในโดเมนอื่นหรือไม่ ในการตอบสนองต่อคำขอ preflight ถ้าคุณฉีดส่วนหัวด้านบนเบราว์เซอร์เข้าใจว่ามันก็โอเคที่จะโทรออกต่อไปและฉันจะได้รับการตอบสนองที่ถูกต้องกับการโทร GET / POST จริงของฉัน คุณสามารถ จำกัด โดเมนที่ได้รับการเข้าถึงโดยใช้ Access-Control-Allow-Origin "," localhost, xvz.com "แทนที่จะเป็น *. (* จะให้สิทธิ์การเข้าถึงโดเมนทั้งหมด)


7
คุณไม่สามารถรวม*สำหรับ...-Originและสำหรับtrue ...-Credentialsมันจะไม่ล้มเหลวสำหรับคำขอที่ไม่ผ่านการรับรอง แต่จะไม่ทำงานสำหรับคำขอที่ได้รับการรับรองเช่นกัน ดูลิงค์ที่ฉันโพสต์ในคำตอบของฉัน
แอนน์

ขอบคุณ Manish Arora ฉันใช้โซลูชันของคุณใน API ของฉันและใช้งานได้ HttpContext.Response.Headers.Add ("การเข้าถึงการควบคุมอนุญาตวิธี", "GET, HEAD, OPTIONS, POST, PUT"); HttpContext.Response.Headers.Add ("Access-Control-Allow-Headers", "Access-Control-Allow-Headers, Origin, Accept, X-Requested ด้วย, เนื้อหาประเภท, Access-Control-Request-Access, Access -Control-ขอส่วนหัว "); HttpContext.Response.Headers.Add ("Access-Control-Allow-Origin-", " localhost: 4200" );
Ramakrishnankt

1
นี่คือสิ่งที่บอกฝั่งเซิร์ฟเวอร์ทั้งหมดหัวข้อการตอบสนองนี้ munging จำเป็นเพราะ "preflight"? ทำไม? โดยเฉพาะอย่างยิ่งสำหรับส่วนหัวมาตรฐานที่สมบูรณ์แบบ? ต้องใช้ HTTP สักพักหนึ่งซึ่งเป็นข่าวสำหรับฉันว่าจำเป็นต้องมีหม้อไอน้ำจำนวนมาก
Samantha Atkins

@ Manish ฉันมีชุดค่าอื่นสำหรับ Access-Control-Allow-Headers ที่ไม่ทำงาน ชุดค่าของคุณทำ ขอบคุณสำหรับการประหยัดเวลาและความยุ่งยาก
azakgaim

มีวิธีการแทนส่วนหัวบางส่วนหรือไม่ เป็นความคิดที่ดีหรือไม่ที่จะใช้สัญลักษณ์แทนส่วนหัวทั้งหมด? เช่นresponse.setHeader("Access-Control-Allow-Headers", "*")? ความหมายของความปลอดภัยในการทำเช่นนี้คืออะไร?
Vadorequest

78

ปัญหานี้แก้ไขได้ด้วย

 "Origin, X-Requested-With, Content-Type, Accept, Authorization"

เฉพาะในโครงการของฉัน (express.js / nodejs)

app.use(function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Methods", "GET,HEAD,OPTIONS,POST,PUT");
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization");
  next();
});

ปรับปรุง:

ข้อผิดพลาดทุกครั้ง: Access-Control-Allow-Headers is not allowed by itself in preflight responseข้อผิดพลาดคุณสามารถเห็นสิ่งผิดปกติกับเครื่องมือของนักพัฒนาซอฟต์แวร์โครม :
ป้อนคำอธิบายรูปภาพที่นี่

ข้อผิดพลาดด้านบนหายไปContent-Typeดังนั้นให้เพิ่มสตริงContent-Typeเข้าไปAccess-Control-Allow-Headers


1
สิ่งนี้จะไม่ได้ผลสำหรับทุกคน ค่าสำหรับ Access-Control-Request-Headers อาจแตกต่างกันไปตามสภาพแวดล้อม รับการเข้าถึงวัตถุคำขอบนเซิร์ฟเวอร์และดัมพ์ค่าสำหรับส่วนหัว "Access-Control-Request-Headers" จากนั้นคัดลอก / วางสิ่งนี้ลงใน response.setHeader ของคุณ ("Access-Control-Allow-Headers", "{paste here}")
ผู้เผยพระวจนะซอฟต์แวร์

1
ตรวจสอบให้แน่ใจว่าคุณสะกดคำว่า Authorization แบบอเมริกันไม่ใช่แบบ Britsh นั่นคือครึ่งชั่วโมงของชีวิตฉันฉันจะไม่กลับมา ขอบคุณสหรัฐอเมริกา! [ถอนหายใจ]
geoidesic

14

คำตอบที่ยอมรับนั้นใช้ได้ แต่ฉันมีปัญหาในการเข้าใจ ดังนั้นนี่คือตัวอย่างง่ายๆในการชี้แจง

ในคำขอ ajax ของฉันฉันมีส่วนหัวการอนุญาตมาตรฐาน

$$(document).on('ajaxStart', function(e){
var auth_token = localStorage.getItem(SB_TOKEN_MOBILE);
if( auth_token ) {
    var xhr = e.detail.xhr;

    xhr.setRequestHeader('**Authorization**', 'Bearer ' + auth_token);
}

รหัสนี้สร้างข้อผิดพลาดในคำถาม สิ่งที่ฉันต้องทำในเซิร์ฟเวอร์ nodejs ของฉันคือการเพิ่มการอนุญาตในส่วนหัวที่อนุญาต:

res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type,**Authorization**');

6

เพื่อเพิ่มคำตอบอื่น ๆ ฉันมีปัญหาเดียวกันและนี่คือรหัสที่ฉันใช้ในเซิร์ฟเวอร์ด่วนของฉันเพื่ออนุญาตให้มีการเรียกใช้ REST:

app.all('*', function(req, res, next) {
  res.header('Access-Control-Allow-Origin', 'URLs to trust of allow');
  res.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
  res.header('Access-Control-Allow-Headers', 'Content-Type');
  if ('OPTIONS' == req.method) {
  res.sendStatus(200);
  } else {
    next();
  }
});

สิ่งที่รหัสนี้โดยทั่วไปคือการสกัดกั้นการร้องขอทั้งหมดและเพิ่มส่วนหัว CORS จากนั้นดำเนินการตามเส้นทางปกติของฉัน เมื่อมีตัวเลือกคำขอมันตอบสนองเฉพาะกับส่วนหัว CORS

แก้ไข: ฉันใช้การแก้ไขนี้สำหรับสองเซิร์ฟเวอร์ express nodejs แยกต่างหากบนเครื่องเดียวกัน ในที่สุดฉันก็แก้ไขปัญหาด้วยพร็อกซีเซิร์ฟเวอร์อย่างง่าย


ขอบคุณ! คุณอธิบายรายละเอียดเกี่ยวกับวิธีการใช้พร็อกซีเซิร์ฟเวอร์แบบง่ายได้หรือไม่?
austin_ce

5

ฉันเพิ่งพบปัญหานี้ด้วยตัวเองในบริบทของ ASP.NET ตรวจสอบให้แน่ใจว่า Web.config ของคุณมีลักษณะดังนี้:

  <system.webServer>
<modules>
  <remove name="FormsAuthentication" />
</modules>

<handlers>
  <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
  <!--<remove name="OPTIONSVerbHandler"/>-->
  <remove name="TRACEVerbHandler" />
  <!--
  <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
  -->
</handlers>

<httpProtocol>
  <customHeaders>
    <add name="Access-Control-Allow-Origin" value="*" />
    <add name="Access-Control-Allow-Headers" value="Content-Type, Authorization" />
    <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
  </customHeaders>
</httpProtocol>

สังเกตเห็นว่าค่าการอนุญาตสำหรับAccess-Control-Allow-Headersคีย์ ฉันไม่มีค่าการอนุญาตการตั้งค่านี้แก้ไขปัญหาของฉัน


5

ดีมากฉันใช้มันในโครงการ silex

$app->after(function (Request $request, Response $response) {
        $response->headers->set('Access-Control-Allow-Origin', '*');
        $response->headers->set("Access-Control-Allow-Credentials", "true");
        $response->headers->set("Access-Control-Allow-Methods", "GET,HEAD,OPTIONS,POST,PUT");
        $response->headers->set("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization");
    });

2
ในขณะที่รหัสนี้อาจตอบคำถามให้บริบทเพิ่มเติมเกี่ยวกับวิธีการและ / หรือทำไมมันแก้ปัญหาจะปรับปรุงค่าระยะยาวของคำตอบ
Badacadabra

4

ใน Chrome:

คำขอส่วนหัวฟิลด์ X-Requested-With ไม่ได้รับอนุญาตจาก Access-Control-Allow-Headers ในการตอบกลับ preflight

สำหรับฉันข้อผิดพลาดนี้ถูกเรียกโดยช่องว่างต่อท้ายใน URL ของการโทรนี้

jQuery.getJSON( url, function( response, status, xhr ) {
   ...
}

3

เพียงเพิ่มที่คุณสามารถใส่ส่วนหัวเหล่านั้นไปยังไฟล์กำหนดค่า Webpack ฉันต้องการพวกเขาเหมือนในกรณีที่ฉันใช้เซิร์ฟเวอร์ webpack dev

devServer: {
    headers: {
      "Access-Control-Allow-Origin": "*",
      "Access-Control-Allow-Credentials": "true",
      "Access-Control-Allow-Methods": "GET,HEAD,OPTIONS,POST,PUT",
      "Access-Control-Allow-Headers": "Origin, X-Requested-With, Content-Type, Accept, Authorization"
},


2

ฉันได้รับข้อผิดพลาดจาก OP ที่ระบุโดยใช้ Django, React และ django-cors-headers lib หากต้องการแก้ไขด้วยสแต็กนี้ให้ทำดังต่อไปนี้:

ใน settings.py เพิ่มด้านล่างตามเอกสารที่เป็นทางการ

from corsheaders.defaults import default_headers

CORS_ALLOW_HEADERS = default_headers + (
'YOUR_HEADER_NAME',
)

2

ปัญหานี้เกิดขึ้นเมื่อเราสร้างส่วนหัวที่กำหนดเองสำหรับการร้องขอคำขอนี้ใช้ HTTP OPTIONSและรวมถึงหลายส่วนหัว

ส่วนหัวที่จำเป็นสำหรับการร้องขอนี้คือAccess-Control-Request-Headersซึ่งควรเป็นส่วนหนึ่งของส่วนหัวการตอบสนองและควรอนุญาตการร้องขอจากแหล่งกำเนิดทั้งหมด บางครั้งก็ต้องการContent-Typeเช่นกันในส่วนหัวของการตอบสนอง ดังนั้นหัวข้อการตอบสนองของคุณควรเป็นเช่นนั้น -

response.header("Access-Control-Allow-Origin", "*"); // allow request from all origin
response.header("Access-Control-Allow-Methods", "GET,HEAD,OPTIONS,POST,PUT");
response.header("Access-Control-Allow-Headers", "Access-Control-Allow-Headers, Origin, X-Requested-With, Content-Type, Accept, Authorization");

1

ในการเรียก Post API เรากำลังส่งข้อมูลในส่วนคำขอ ดังนั้นถ้าเราจะส่งข้อมูลโดยการเพิ่มส่วนหัวพิเศษใด ๆ ในการโทร API จากนั้นจะมีการเรียกใช้ OPTIONS API ครั้งแรกจากนั้นโพสต์การโทรจะเกิดขึ้น ดังนั้นคุณต้องจัดการ OPTION API ก่อน

คุณสามารถจัดการปัญหาโดยการเขียนตัวกรองและภายในที่คุณต้องตรวจสอบการโทรตัวเลือกการโทร API และส่งคืนสถานะ 200 OK ด้านล่างนี้คือตัวอย่างรหัส:

package com.web.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.catalina.connector.Response;

public class CustomFilter implements Filter {
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        HttpServletRequest httpRequest = (HttpServletRequest) req;
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "x-requested-with, Content-Type");
        if (httpRequest.getMethod().equalsIgnoreCase("OPTIONS")) {
            response.setStatus(Response.SC_OK);
        }
        chain.doFilter(req, res);
    }

    public void init(FilterConfig filterConfig) {
        // TODO
    }

    public void destroy() {
        // Todo
    }

}

1

หากคุณพยายามเพิ่มส่วนหัวที่กำหนดเองบนส่วนหัวคำขอคุณต้องแจ้งให้เซิร์ฟเวอร์ทราบว่าส่วนหัวที่เฉพาะเจาะจงได้รับอนุญาต สถานที่ที่ต้องทำนั้นอยู่ในคลาสที่กรองการร้องขอ ในตัวอย่างที่แสดงด้านล่างชื่อส่วนหัวที่กำหนดเองคือ "type":

public class CorsFilter implements Filter {
    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
        response.setHeader("Access-Control-Allow-Origin",  request.getHeader("Origin"));
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Methods", "GET,PUT,POST,DELETE,PATCH,OPTIONS");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With, remember-me, Authorization, type ");
        response.setHeader("Access-Control-Expose-Headers","Authorization");
    }
}

1

หลังจากใช้เวลาเกือบวันฉันเพิ่งค้นพบว่าการเพิ่มโค้ดด้านล่างสองรหัสเพื่อแก้ไขปัญหาของฉัน

เพิ่มสิ่งนี้ใน Global.asax

protected void Application_BeginRequest()
{
  if (Request.HttpMethod == "OPTIONS")
  {
    Response.StatusCode = (int)System.Net.HttpStatusCode.OK;             
    Response.End();
  }
}

และในเว็บกำหนดค่าให้เพิ่มด้านล่าง

<httpProtocol>
  <customHeaders>
    <add name="Access-Control-Allow-Origin" value="*" />        
    <add name="Access-Control-Allow-Methods" value="*" />
    <add name="Access-Control-Allow-Headers" value="Content-Type, Authorization" />
  </customHeaders>
</httpProtocol>

1

ฉันก็ประสบปัญหาเดียวกันใน Angular 6 ฉันแก้ไขปัญหาโดยใช้รหัสด้านล่าง เพิ่มรหัสในไฟล์ component.ts

import { HttpHeaders } from '@angular/common/http';

headers;

constructor() {
    this.headers = new HttpHeaders();
    this.headers.append('Access-Control-Allow-Headers', 'Authorization');
}

getData() {
    this.http.get(url,this.headers). subscribe (res => {
    // your code here...
})}

0

ปัญหาเดียวกันนี้ที่ฉันกำลังเผชิญ

ฉันทำการเปลี่ยนแปลงง่าย ๆ

  <modulename>.config(function($httpProvider){
    delete $httpProvider.defaults.headers.common['X-Requested-With'];
});

0

ข้อความมีความชัดเจนว่าไม่อนุญาตให้ใช้ 'การอนุญาต' ใน API ตั้งค่า
Access-Control-Allow-Headers: "Content-Type, Authorization"


0
const express = require('express')
const cors = require('cors')
const app = express()

app.get('/with-cors', cors(), (req, res, next) => {
  res.json({ msg: 'WHOAH with CORS it works! 🔝 🎉' })
})

การเพิ่มฟังก์ชั่น cors ใน get เป็นสิ่งที่ใช้ได้ผลสำหรับฉัน

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