Я пытаюсь получить данные из REST API HP Alm. Он неплохо работает с небольшим скриптом curl - я получаю свои данные.

Теперь сделать это с помощью JavaScript, fetch и ES6 (более или менее) кажется более серьезной проблемой. Я все время получаю это сообщение об ошибке:

Не удается загрузить API-интерфейс Fetch. Ответ на предполетный запрос не пройти проверку контроля доступа: заголовок 'Access-Control-Allow-Origin' не присутствует на запрошенном ресурсе. Origin 'http://127.0.0.1: 3000' равно поэтому не разрешен доступ. Ответ имел код состояния HTTP 501. Если непрозрачный ответ соответствует вашим потребностям, установите режим запроса на 'no-cors' для выборки ресурса с отключенным CORS.

Я понимаю, что это связано с тем, что я пытаюсь получить эти данные из своего локального хоста, и решение должно использовать CORS. Теперь я думал, что действительно это сделал, но почему-то он либо игнорирует то, что я пишу в заголовке, либо проблема в другом?

Итак, есть проблема с реализацией? Я что делаю неправильно? К сожалению, я не могу проверить логи сервера. Я действительно немного застрял здесь.

function performSignIn() {

  let headers = new Headers();

  headers.append('Content-Type', 'application/json');
  headers.append('Accept', 'application/json');

  headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
  headers.append('Access-Control-Allow-Credentials', 'true');

  headers.append('GET', 'POST', 'OPTIONS');

  headers.append('Authorization', 'Basic ' + base64.encode(username + ":" + password));

  fetch(sign_in, {
      //mode: 'no-cors',
      credentials: 'include',
      method: 'POST',
      headers: headers
    })
    .then(response => response.json())
    .then(json => console.log(json))
    .catch(error => console.log('Authorization failed : ' + error.message));
}

Я использую Chrome. Я также пробовал использовать этот плагин Chrome CORS, но затем получаю другое сообщение об ошибке:

Значение заголовка Access-Control-Allow-Origin в ответе не должен быть подстановочным знаком '*', когда режим учетных данных запроса 'включают'. Следовательно, источник 'http://127.0.0.1: 3000' не допускается. доступ. Режим учетных данных запросов, инициированных XMLHttpRequest управляется атрибутом withCredentials.

Ответы (21)

This answer covers a lot of ground, so it’s divided into three parts:

  • How to use a CORS proxy to get around “No Access-Control-Allow-Origin header” problems
  • How to avoid the CORS preflight
  • How to fix “Access-Control-Allow-Origin header must not be the wildcard” problems

How to use a CORS proxy to avoid “No Access-Control-Allow-Origin header” problems

If you don’t control the server your frontend code is sending a request to, and the problem with the response from that server is just the lack of the necessary Access-Control-Allow-Origin header, you can still get things to work—by making the request through a CORS proxy.

You can easily run your own proxy with code from https://github.com/Rob--W/cors-anywhere/.
You can also easily deploy your own proxy to Heroku in just 2-3 minutes, with 5 commands:

git clone https://github.com/Rob--W/cors-anywhere.git
cd cors-anywhere/
npm install
heroku create
git push heroku master

After running those commands, you’ll end up with your own CORS Anywhere server running at, e.g., https://cryptic-headland-94862.herokuapp.com/.

Now, prefix your request URL with the URL for your proxy:

https://cryptic-headland-94862.herokuapp.com/https://example.com

Adding the proxy URL as a prefix causes the request to get made through your proxy, which:

  1. Forwards the request to https://example.com.
  2. Receives the response from https://example.com.
  3. Adds the Access-Control-Allow-Origin header to the response.
  4. Passes that response, with that added header, back to the requesting frontend code.

The browser then allows the frontend code to access the response, because that response with the Access-Control-Allow-Origin response header is what the browser sees.

This works even if the request is one that triggers browsers to do a CORS preflight OPTIONS request, because in that case, the proxy also sends the Access-Control-Allow-Headers and Access-Control-Allow-Methods headers needed to make the preflight succeed.


How to avoid the CORS preflight

The code in the question triggers a CORS preflight—since it sends an Authorization header.

https://developer.mozilla.org/docs/Web/HTTP/Access_control_CORS#Preflighted_requests

Even without that, the Content-Type: application/json header will also trigger a preflight.

What “preflight” means: before the browser tries the POST in the code in the question, it first sends an OPTIONS request to the server, to determine if the server is opting-in to receiving a cross-origin POST that has Authorization and Content-Type: application/json headers.

It works pretty well with a small curl script - I get my data.

To properly test with curl, you must emulate the preflight OPTIONS the browser sends:

curl -i -X OPTIONS -H "Origin: http://127.0.0.1:3000" \
    -H 'Access-Control-Request-Method: POST' \
    -H 'Access-Control-Request-Headers: Content-Type, Authorization' \
    "https://the.sign_in.url"

…with https://the.sign_in.url replaced by whatever your actual sign_in URL is.

The response the browser needs from that OPTIONS request must have headers like this:

Access-Control-Allow-Origin:  http://127.0.0.1:3000
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type, Authorization

If the OPTIONS response doesn’t include those headers, the browser will stop right there and never attempt to send the POST request. Also, the HTTP status code for the response must be a 2xx—typically 200 or 204. If it’s any other status code, the browser will stop right there.

The server in the question responds to the OPTIONS request with a 501 status code, which apparently means it’s trying to indicate it doesn’t implement support for OPTIONS requests. Other servers typically respond with a 405 “Method not allowed” status code in this case.

So you’ll never be able to make POST requests directly to that server from your frontend JavaScript code if the server responds to that OPTIONS request with a 405 or 501 or anything other than a 200 or 204 or if doesn’t respond with those necessary response headers.

The way to avoid triggering a preflight for the case in the question would be:

  • if the server didn’t require an Authorization request header but instead, e.g., relied on authentication data embedded in the body of the POST request or as a query param
  • if the server didn’t require the POST body to have a Content-Type: application/json media type but instead accepted the POST body as application/x-www-form-urlencoded with a parameter named json (or whatever) whose value is the JSON data

How to fix “Access-Control-Allow-Origin header must not be the wildcard” problems

I am getting another error message:

The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. Origin 'http://127.0.0.1:3000' is therefore not allowed access. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.

For requests that have credentials, browsers won’t let your frontend JavaScript code access the response if the value of the Access-Control-Allow-Origin header is *. Instead the value in that case must exactly match your frontend code’s origin, http://127.0.0.1:3000.

See Credentialed requests and wildcards in the MDN HTTP access control (CORS) article.

If you control the server you’re sending the request to, a common way to deal with this case is to configure the server to take the value of the Origin request header, and echo/reflect that back into the value of the Access-Control-Allow-Origin response header; e.g., with nginx:

add_header Access-Control-Allow-Origin $http_origin

But that’s just an example; other (web) server systems have similar ways to echo origin values.


I am using Chrome. I also tried using that Chrome CORS Plugin

That Chrome CORS plugin apparently just simplemindedly injects an Access-Control-Allow-Origin: * header into the response the browser sees. If the plugin were smarter, what it would be doing is setting the value of that fake Access-Control-Allow-Origin response header to the actual origin of your frontend JavaScript code, http://127.0.0.1:3000.

So avoid using that plugin, even for testing. It’s just a distraction. To test what responses you get from the server with no browser filtering them, you’re better off using curl -H as above.


As far as the frontend JavaScript code for the fetch(…) request in the question:

headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');

Remove those lines. The Access-Control-Allow-* headers are response headers. You never want to send them in requests. The only effect of that is to trigger a browser to do a preflight.

В моем случае я использую решение ниже

Front-end или Angular

post(
    this.serverUrl, dataObjToPost,
    {
      headers: new HttpHeaders({
           'Content-Type':  'application/json',
         })
    }
)

back-end (я использую php)

header("Access-Control-Allow-Origin: http://localhost:4200");
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header("Access-Control-Allow-Headers: Content-Type, Authorization");

$postdata = file_get_contents("php://input");
$request = json_decode($postdata);
print_r($request);

Если вы используете NodeJS / Express в качестве серверной части и ReactJS / axios в качестве интерфейса в среде разработки в MacOS, вам необходимо запустить обе стороны под https. Ниже показано, что у меня наконец сработало (после многих часов глубокого погружения и тестирования):

Шаг 1. Создайте сертификат SSL

Просто следуйте инструкциям из Как заставить HTTPS работать в вашей локальной среде разработки за 5 минут

У вас будет пара файлов, которые будут использоваться в качестве учетных данных для запуска https-сервера и ReactJS в Интернете:

server.key & server.crt

Вам необходимо скопировать их в корневые папки как на передней, так и на внутренней стороне (в производственной среде вы можете рассмотреть возможность копирования их в ./ssh для серверной части).

Шаг 2: Настройка серверной части

Я читал много ответов, предлагающих использовать пакет 'cors' или даже настройку ('Access-Control-Allow-Origin', '*'), которая похожа на высказывание: «Хакеры приветствуются на моем веб-сайте». Просто сделайте так:

import express from 'express';
const emailRouter = require('./routes/email');  // in my case, I was sending an email through a form in ReactJS
const fs = require('fs');
const https = require('https');

const app = express();
const port = 8000;

// CORS (Cross-Origin Resource Sharing) headers to support Cross-site HTTP requests
app.all('*', (req, res, next) => {
    res.header("Access-Control-Allow-Origin", "https://localhost:3000");
    next();
});

// Routes definition
app.use('/email', emailRouter);

// HTTPS server
const credentials = {
  key: fs.readFileSync('server.key'),
  cert: fs.readFileSync('server.crt')
};

const httpsServer = https.createServer(credentials, app);
httpsServer.listen(port, () => {
    console.log(`Back-end running on port ${port}`);
});

Если вы хотите проверить, в порядке ли https, вы можете заменить константу httpsServer на следующую:

https.createServer(credentials, (req: any, res: any) => {
  res.writeHead(200);
  res.end("hello world from SSL\n");
}).listen(port, () => {
  console.log(`HTTPS server listening on port ${port}...`);
});

А затем откройте его из веб-браузера: https://localhost: 8000 /

Шаг 3: Настройка внешнего интерфейса

Это запрос axios от интерфейса ReactJS:

    await axios.get(`https://localhost:8000/email/send`, {
        params: {/* whatever data you want to send */ },
        headers: {
            'Content-Type': 'application/json',
        }
    })

И теперь вам нужно запустить вашу сеть ReactJS в режиме https, используя учетные данные для SSL, которые мы уже создали. Введите это в свой терминал MacOS:

HTTPS=true SSL_CRT_FILE=server.crt SSL_KEY_FILE=server.key npm start

На этом этапе вы отправляете запрос через https-соединение через порт 3000 из вашего внешнего интерфейса, который должен быть получен через https-соединение через порт 8000 на вашем внутреннем интерфейсе. CORS должен быть доволен этим;)

The problem arose because you added the following code as request header in your front-end :

headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');

Those headers belong to response, not request. So remove them, including the line :

headers.append('GET', 'POST', 'OPTIONS');

Your request had 'Content-Type: application/json', hence triggered what is called CORS preflight. This caused the browser sent the request with OPTIONS method. See CORS preflight for detailed information.

Therefore in your back-end, you have to handle this preflighted request by returning the response headers which include :

Access-Control-Allow-Origin : http://localhost:3000
Access-Control-Allow-Credentials : true
Access-Control-Allow-Methods : GET, POST, OPTIONS
Access-Control-Allow-Headers : Origin, Content-Type, Accept

Of course, the actual syntax depends on the programming language you use for your back-end.

In your front-end, it should be like so :

function performSignIn() {
    let headers = new Headers();

    headers.append('Content-Type', 'application/json');
    headers.append('Accept', 'application/json');
    headers.append('Authorization', 'Basic ' + base64.encode(username + ":" +  password));
    headers.append('Origin','http://localhost:3000');

    fetch(sign_in, {
        mode: 'cors',
        credentials: 'include',
        method: 'POST',
        headers: headers
    })
    .then(response => response.json())
    .then(json => console.log(json))
    .catch(error => console.log('Authorization failed : ' + error.message));
}

Только мои два цента ... относительно Как использовать прокси-сервер CORS для решения проблем «Нет Access-Control-Allow-Origin header»

Для тех из вас, кто работает с php на бэкэнде, развернуть «прокси-сервер CORS» так же просто, как:

  1. создайте файл с именем no-cors.php со следующим содержимым:

    $ URL = $ _GET ['url'];
    echo json_encode (file_get_contents ($ URL));
    умри();
    
  2. на вашем интерфейсе, сделайте что-то вроде:

    fetch ('https://example.com/no-cors.php' + '? Url =' + url)
      .then (response => {* / Обработка ответа / *}) `
    

В моем случае веб-сервер заблокировал метод "OPTIONS"

Проверьте свой веб-сервер на наличие метода опций

Я использую "webtier"

/www/webtier/domains/[имя домена] /config/fmwconfig/components/OHS/VCWeb1/httpd.conf


  RewriteEngine on
  RewriteCond %{REQUEST_METHOD} ^OPTIONS
  RewriteRule .* . [F]

изменить на


  RewriteEngine off
  RewriteCond %{REQUEST_METHOD} ^OPTIONS
  RewriteRule .* . [F]

Если вы получаете эту ошибку при развертывании приложения React для netlify, выполните следующие действия.

шаг 1: Создайте файл netlify.toml в корневой папке вашего приложения для реагирования.

шаг 2: Скопируйте и вставьте этот код:

`[[redirects]]
    from = "/cors-proxy/*"
    to = ":splat"
    status = 200
    force = true`

enter image description here

step3: обновите api fetch / axios следующим образом:

enter image description here

Мне потребовалось время, чтобы понять это.

Используйте указанный ниже модуль npm. Это практически спасло жизни.

https://www.npmjs.com/package/local-cors-proxy

вы получаете ошибку CORS, например, как показано ниже URL

https://www.google.co.in/search/list

После успешной установки (local-cors-proxy) global npm install -g local-cors-proxy и укажите URL-адрес прокси-сервера CORS url. Например, здесь ниже проблема CORS, попадающая на localhost. Поэтому вам нужно добавить доменное имя и порт для домена проблемы CORS.

lcp --proxyUrl https://www.google.co.in --port 8010

После успешной установки будет сгенерирован URL-адрес локального прокси, как показано ниже.

http://localhost: 8010 / прокси

Используйте это доменное имя в URL-адресе API вашего проекта. Полный URL API

http://localhost: 8010 / прокси / поиск / список

Чтобы получить ответ о проблеме без CORS в вашем локальном проекте.

Я знаю, что опаздываю, но это кому-то поможет

Возможная причина проблем CORS

  • Проверьте заголовки доступа на стороне сервера: См. Эту ссылку
  • Проверьте, какой заголовок запроса получает от сервера в браузере, на изображении ниже показаны заголовки. enter image description here
  • Если вы используете метод fetch и пытаетесь получить доступ к запросу Cross-origin, убедитесь, что есть режим : cors. См. Эту ссылку
  • Иногда, если есть проблема в программе, вы также получаете проблему CORS, поэтому убедитесь, что ваш код работает правильно.
  • Обязательно обработайте метод OPTION в вашем API.

Для узла js express backend я использую это :)

app.use (function (req, res, next) {
  res.header ("Access-Control-Allow-Origin", "ВАШ-ДОМЕН.TLD"); // обновляем в соответствии с доменом, из которого вы будете делать запрос
  res.header ("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
  следующий();
});

Подробности: https://enable-cors.org/server_expressjs.html

когда клиент использует для вызова нашей серверной службы со своего хоста username.companyname.com, он использует для получения вышеуказанной ошибки

Требуются две вещи:

  1. при отправке ответа отправьте заголовок, ключ которого - Access-Control-Allow-Origin, а значение - *

     context.Writer.Header () ["Access-Control-Allow-Origin"] = [] string {"*"} // важно, чтобы избежать ошибки CORS
    
  2. используйте библиотеку CORS golang, чтобы установить AllowCredentials в значение false и AllowAllOrigins в значение true enter image description here

итак, я делаю эту ошибку много раз, потому что я составил «чек-лист» для всех вас.

  • Включите CORS в своем проекте: если вы используете NodeJS (например), вы можете использовать:

    npm install cors; импортные корсы от «корс»; app.use (cors ());

  • Вы можете вручную установить такие заголовки (если хотите):

    app.use ((req, res, next) => { res.setHeader ('Доступ-Контроль-Разрешить-Происхождение', '*'); res.setHeader ('Access-Control-Allow-Headers', 'Источник, X-Requested-With, Content-Type, Accept, Authortization');
    res.setHeader ('Acces-Control-Allow-Methods', 'GET, POST, PATCH, DELETE');

  • Не забудьте добавить http: // к вашей ссылке API в вашем внешнем проекте, некоторые браузеры, такие как Chrome, НЕ принимают запрос с использованием CORS, если URL-адрес запроса не является http / https:

http://localhost: 3000 / API

  • Проверьте, использует ли ваш проект proxy.config.js, см. Здесь:

https://levelup.gitconnected.com/fixing-cors-errors-with-angular-cli-proxy-e5e0ef143f85

добавление mode: no-cors может избежать проблемы cors в api.

fetch(sign_in, {
        mode: 'no-cors',
        credentials: 'include',
        method: 'POST',
        headers: headers
    })
    .then(response => response.json())
    .then(json => console.log(json))
    .catch(error => console.log('Authorization failed : ' + error.message));
}

Я работал с Spring REST и решил его, добавив AllowedMethods в WebMvcConfigurer.

@Value( "${app.allow.origins}" )
    private String allowOrigins;    
@Bean
public WebMvcConfigurer corsConfigurer() {
            System.out.println("allow origin: "+allowOrigins);
            return new WebMvcConfigurerAdapter() {
                @Override
                public void addCorsMappings(CorsRegistry registry) {
                    registry.addMapping("/**")
                    //.allowedOrigins("http://localhost")
                    .allowedOrigins(allowOrigins)
                    .allowedMethods("PUT", "DELETE","GET", "POST");
                }
            };
        }

Использование dataType: 'jsonp' у меня сработало.

   async function get_ajax_data(){
       var _reprojected_lat_lng = await $.ajax({
                                type: 'GET',
                                dataType: 'jsonp',
                                data: {},
                                url: _reprojection_url,
                                error: function (jqXHR, textStatus, errorThrown) {
                                    console.log(jqXHR)
                                },
                                success: function (data) {
                                    console.log(data);

                                    // note: data is already json type, you
                                    //       just specify dataType: jsonp
                                    return data;
                                }
                            });


 } // function               

Удалите это:

credentials: 'include',

Я сталкивался с этой ошибкой несколько раз за последние несколько лет - по-видимому, она неожиданно появлялась на ранее работающем веб-сайте. Я определил, что Chrome (и, возможно, другие браузеры) могут возвращать эту ошибку, когда на сервере возникает какая-то несвязанная ошибка, которая не позволяет ему обработать запрос CORS (и до возврата ошибки HTTP 500). Все это произошло в среде .Net Core, не уверен, что это произойдет в других средах. В любом случае, если ваш код функционировал раньше и кажется правильным, подумайте об отладке, чтобы определить, возникает ли какая-либо другая ошибка, прежде чем вы сойдете с ума, пытаясь решить ошибку, которой на самом деле нет.

Попробуйте добавить все эти заголовки в этот код ниже Перед каждым маршрутом, который вы определяете в своем приложении, а не после маршрутов

app.use((req, res, next) =>{
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Headers','Origin, X-Requested-With, Content-Type,Accept, Authortization');  
res.setHeader('Acces-Control-Allow-Methods','GET, POST, PATCH, DELETE');

Если ваш API написан на asp dot net core. Затем выполните следующие шаги:

  • Установить пакет Microsoft.AspNetCore.Cors.

  • Добавьте строку ниже в метод ConfigureServices в Startup.cs:

    services.AddCors ();
    
  • Добавьте строку ниже в методе Configure в startup.cs:

    app.UseCors (options =>
         options.WithOrigins ("http://localhost: 8080")
                .AllowAnyHeader ()
                .AllowAnyMethod ());
    
    убедитесь, что вы добавили это раньше - app.UseRouting ();
    

При использовании Nodejs, если вы используете маршрутизаторы, не забудьте добавить корс перед маршрутизаторами. В противном случае вы все равно получите ошибку cors. Как показано ниже:

const cors = require('cors');

const userRouter = require('./routers/user');

expressApp = express();
expressApp.use(cors());
expressApp.use(express.json());
expressApp.use(userRouter);

Эта ошибка возникает, когда URL-адрес клиента и URL-адрес сервера не совпадают, включая номер порта. В этом случае вам необходимо включить службу CORS, которая представляет собой совместное использование ресурсов из разных источников.

Если вы размещаете службу Spring REST, вы можете найти ее в сообщении блога Поддержка CORS в Spring Framework.

Если вы размещаете сервис на сервере Node.js, то

  1. Остановить сервер Node.js.
  2. npm install cors --save
  3. Добавьте следующие строки в свой server.js
const cors=require("cors");
const corsOptions ={
   origin:'*', 
   credentials:true,            //access-control-allow-credentials:true
   optionSuccessStatus:200,
}

app.use(cors(corsOptions)) // Use this after the variable declaration

2022 WebDevInsider