Trường tiêu đề yêu cầu Kiểm soát truy cập-Cho phép-Tiêu đề không được phép trong chính phản hồi


234

Tôi đã gặp các vấn đề về CORS nhiều lần và thường có thể khắc phục nhưng tôi muốn thực sự hiểu bằng cách xem điều này từ mô hình ngăn xếp MEAN.

Trước đây tôi chỉ đơn giản là thêm phần mềm trung gian trong máy chủ cấp tốc của mình để nắm bắt những thứ này, nhưng có vẻ như có một loại hook-hook nào đó đang lỗi trong yêu cầu của tôi.

Trường tiêu đề yêu cầu Access-Control-Allow-Headers không được phép bởi Access-Control-Allow-Headers trong phản ứng trước

Tôi cho rằng tôi có thể làm điều này:

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

hoặc tương đương nhưng điều này dường như không khắc phục được. Tất nhiên tôi cũng đã thử

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

Vẫn không có may mắn.

Câu trả lời:


245

Khi bạn bắt đầu chơi xung quanh với các tiêu đề yêu cầu tùy chỉnh, bạn sẽ nhận được một đèn pha CORS. Đây là một yêu cầu sử dụng OPTIONSđộng từ HTTP và bao gồm một số tiêu đề, một trong số đó là Access-Control-Request-Headersliệt kê các tiêu đề mà khách hàng muốn đưa vào yêu cầu.

Bạn cần trả lời trước ánh sáng CORS đó với các tiêu đề CORS thích hợp để thực hiện công việc này. Một trong số đó là thực sự Access-Control-Allow-Headers. Tiêu đề đó cần chứa cùng các giá trị mà Access-Control-Request-Headerstiêu đề chứa (hoặc nhiều hơn).

https://fetch.spec.whatwg.org/#http-cors-protatio giải thích thiết lập này chi tiết hơn.


41
Nếu bạn đang sử dụng Chrome và bạn không chắc chắn những tiêu đề nào đang được yêu cầu, hãy sử dụng Bảng điều khiển dành cho nhà phát triển, Mạng chọn cuộc gọi đang được thực hiện và bạn có thể xem những tiêu đề nào đang được yêu cầu bởiAccess-Control-Request-Headers
Lionel Morrison

5
Tùy chọn Bảng điều khiển dành cho nhà phát triển là một lựa chọn tốt. Bạn cũng có thể tìm thấy những gì bạn cần bằng cách truy cập vào đối tượng yêu cầu trên máy chủ và bỏ các giá trị cho các tiêu đề, nhưng cụ thể là giá trị tiêu đề cho "Tiêu đề kiểm soát truy cập-yêu cầu". Sau đó, sao chép / dán phần này vào phản hồi của bạn.setHeader ("Kiểm soát truy cập-Cho phép-Tiêu đề", "{dán vào đây}")
Tiên tri phần mềm

7
làm ơn ví dụ!
Demodave

5
@ Hãy nhớ một ví dụ về điều này đối với tôi làheader("Access-Control-Allow-Headers: Content-Type")
Joshua Duxbury

1
@LionelMorrison, sử dụng các công cụ phát triển chrome cho các tiêu đề phù hợp. giải thích tốt !!!
Savina Chandla

119

Đây là những gì bạn cần thêm để làm cho nó hoạt động.

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");

Trình duyệt gửi yêu cầu preflight (với loại phương thức TÙY CHỌN) để kiểm tra xem dịch vụ được lưu trữ trên máy chủ có được phép truy cập từ trình duyệt trên một tên miền khác không. Đáp lại yêu cầu preflight nếu bạn thực hiện các tiêu đề trên, trình duyệt hiểu rằng bạn có thể thực hiện các cuộc gọi tiếp theo và tôi sẽ nhận được phản hồi hợp lệ cho cuộc gọi GET / POST thực tế của mình. bạn có thể hạn chế tên miền được cấp quyền truy cập bằng cách sử dụng Access-Control-allow-Origin "," localhost, xvz.com "thay vì *. (* sẽ cấp quyền truy cập cho tất cả các miền)


7
Bạn không thể kết hợp *cho ...-Origintruecho ...-Credentials. Nó sẽ không thất bại đối với các yêu cầu không được xác thực, nhưng nó cũng sẽ không hoạt động đối với các yêu cầu được chứng thực. Xem liên kết tôi đã đăng trong câu trả lời của tôi.
Anne

Cảm ơn Manish Arora, tôi đã sử dụng giải pháp của bạn trong api của tôi và nó đã hoạt động. HttpContext.Response.Headers.Add ("Truy cập-Kiểm soát-Cho phép-Phương thức", "NHẬN, ĐẦU, TÙY CHỌN, POST, PUT"); HttpContext.Response.Headers.Add ("Access-Control-allow-Headers", "Access-Control-allow-Headers, Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Request, Access -Control-Request-Headers "); HttpContext.Response.Headers.Add ("Truy cập-Kiểm soát-Cho phép-Xuất xứ", " localhost: 4200" );
Ramakrishnankt

1
Điều này nói rằng phía máy chủ tất cả munging tiêu đề phản hồi này là cần thiết vì "preflight"? Tại sao? Đặc biệt là cho các tiêu đề hoàn hảo tiêu chuẩn? Đã sử dụng HTTP được một thời gian, có một tin tức với tôi là cần rất nhiều bản tóm tắt.
Samantha Atkins

@manish Tôi đã có một bộ giá trị khác cho Tiêu đề kiểm soát truy cập cho phép không hoạt động. Tập hợp các giá trị của bạn đã làm. Cảm ơn vì đã tiết kiệm thời gian và sự thất vọng.
azakgaim

Có cách nào để ký tự đại diện một số tiêu đề? Có phải là một ý tưởng tồi để ký tự đại diện tất cả các tiêu đề? Chẳng hạn như response.setHeader("Access-Control-Allow-Headers", "*")? Ý nghĩa bảo mật của việc làm này là gì?
Vadorequest

78

Vấn đề này được giải quyết với

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

Đặc biệt trong dự án của tôi (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();
});

Cập nhật:

Mỗi lần lỗi: Access-Control-Allow-Headers is not allowed by itself in preflight responselỗi bạn có thể thấy lỗi gì với công cụ phát triển chrome :
nhập mô tả hình ảnh ở đây

thiếu lỗi ở trên Content-Typenên thêm chuỗi Content-TypevàoAccess-Control-Allow-Headers


1
Điều này sẽ không làm việc cho tất cả mọi người. Giá trị cho Tiêu đề kiểm soát truy cập-yêu cầu có thể thay đổi tùy theo môi trường. Nhận quyền truy cập vào đối tượng yêu cầu trên máy chủ và kết xuất các giá trị cho tiêu đề "Truy cập-Kiểm soát-Yêu cầu-Tiêu đề". Sau đó, sao chép / dán phần này vào phản hồi của bạn.setHeader ("Kiểm soát truy cập-Cho phép-Tiêu đề", "{dán vào đây}")
Tiên tri phần mềm

1
Ngoài ra, hãy đảm bảo bạn đánh vần Ủy quyền theo cách của người Mỹ chứ không phải theo cách của Britsh. Đó là nửa giờ của cuộc đời tôi, tôi sẽ không trở lại. Thx Hoa Kỳ! [thở dài]
địa lý

14

Câu trả lời được chấp nhận là ok, nhưng tôi đã gặp khó khăn để hiểu nó. Vì vậy, đây là một ví dụ đơn giản để làm rõ nó.

Trong yêu cầu ajax của tôi, tôi đã có một tiêu đề Ủy quyền tiêu chuẩn.

$$(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);
}

Mã này tạo ra lỗi trong câu hỏi. Những gì tôi phải làm trong máy chủ nodejs của mình là thêm Ủy quyền trong các tiêu đề được phép:

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

6

Để thêm vào các câu trả lời khác. Tôi gặp vấn đề tương tự và đây là mã tôi đã sử dụng trong máy chủ cấp tốc của mình để cho phép các cuộc gọi 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();
  }
});

Những gì mã này về cơ bản là chặn tất cả các yêu cầu và thêm các tiêu đề CORS, sau đó tiếp tục với các tuyến thông thường của tôi. Khi có yêu cầu TÙY CHỌN, nó chỉ đáp ứng với các tiêu đề CORS.

EDIT: Tôi đã sử dụng bản sửa lỗi này cho hai máy chủ tốc độ nodejs riêng biệt trên cùng một máy. Cuối cùng, tôi đã khắc phục sự cố với một máy chủ proxy đơn giản.


Cảm ơn! Bạn có thể giải thích về cách bạn sử dụng một máy chủ proxy đơn giản không?
austin_ce

5

Tôi vừa mới gặp vấn đề này, trong bối cảnh ASP.NET, hãy đảm bảo Web.config của bạn trông như thế này:

  <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>

Lưu ý giá trị ủy quyền cho Access-Control-Allow-Headerskhóa. Tôi đã thiếu giá trị Ủy quyền, cấu hình này giải quyết vấn đề của tôi.


5

Rất tốt tôi đã sử dụng điều này trong một dự án 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
Mặc dù mã này có thể trả lời câu hỏi, việc cung cấp ngữ cảnh bổ sung về cách thức và / hoặc lý do giải quyết vấn đề sẽ cải thiện giá trị lâu dài của câu trả lời.
Badacadabra

4

Trong Chrome:

Trường tiêu đề yêu cầu X-Requested-With không được phép bởi Access-Control-Allow-Headers trong phản ứng preflight.

Đối với tôi, lỗi này được kích hoạt bởi một khoảng trắng ở URL của cuộc gọi này.

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

3

Chỉ cần thêm rằng bạn cũng có thể đặt các tiêu đề đó vào tệp cấu hình Webpack. Tôi cần chúng như trong trường hợp của tôi vì tôi đang chạy máy chủ phát triển webpack.

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"
},

3

res.setHeader ('Kiểm soát truy cập-Cho phép-Tiêu đề', '*');


2

Tôi đã nhận được lỗi mà OP đã nêu khi sử dụng Django, React và django-cors-headers lib. Để sửa nó với ngăn xếp này, hãy làm như sau:

Trong phần cài đặt, hãy thêm phần dưới đây vào mỗi tài liệu chính thức .

from corsheaders.defaults import default_headers

CORS_ALLOW_HEADERS = default_headers + (
'YOUR_HEADER_NAME',
)

2

vấn đề này xảy ra khi chúng tôi thực hiện tiêu đề tùy chỉnh cho yêu cầu. Yêu cầu này sử dụng HTTP OPTIONSvà bao gồm một số tiêu đề.

Tiêu đề bắt buộc cho yêu cầu này là Access-Control-Request-Headers, một phần của tiêu đề phản hồi và sẽ cho phép yêu cầu từ tất cả các nguồn gốc. Đôi khi nó cũng cần Content-Typetrong tiêu đề của phản ứng. Vì vậy, tiêu đề phản hồi của bạn nên như thế -

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

Trong cuộc gọi API bài viết, chúng tôi đang gửi dữ liệu trong phần yêu cầu. Vì vậy, nếu chúng tôi sẽ gửi dữ liệu bằng cách thêm bất kỳ tiêu đề bổ sung nào vào lệnh gọi API. Sau đó, cuộc gọi API TÙY CHỌN đầu tiên sẽ xảy ra và sau đó gửi cuộc gọi sẽ xảy ra. Do đó, trước tiên bạn phải xử lý lệnh gọi API TÙY CHỌN.

Bạn có thể xử lý sự cố bằng cách viết bộ lọc và bên trong bạn phải kiểm tra lệnh gọi API tùy chọn và trả về trạng thái 200 OK. Dưới đây là mã mẫu:

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

Nếu bạn đang cố gắng thêm một tiêu đề tùy chỉnh trên các tiêu đề yêu cầu, bạn phải cho máy chủ biết rằng tiêu đề cụ thể được phép diễn ra. Nơi để làm điều đó là trong lớp lọc các yêu cầu. Trong ví dụ hiển thị bên dưới, tên tiêu đề tùy chỉnh là "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

Sau khi dành gần một ngày, tôi mới phát hiện ra rằng việc thêm hai mã dưới đây đã giải quyết được vấn đề của tôi.

Thêm phần này vào Global.asax

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

và trong cấu hình web, thêm vào bên dưới

<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

Tôi cũng gặp phải vấn đề tương tự trong Angular 6. Tôi đã giải quyết vấn đề bằng cách sử dụng mã dưới đây. Thêm mã trong tập tin thành phần.

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

Vấn đề tương tự tôi đã phải đối mặt.

Tôi đã làm một thay đổi đơn giản.

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

0

Thông báo rõ ràng rằng 'Ủy quyền' không được phép trong API. Đặt
tiêu đề kiểm soát truy cập-cho phép-tiêu đề: "Loại nội dung, ủy quyền"


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! 🔝 🎉' })
})

Thêm cors trong hàm get là những gì làm việc cho tôi

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.