Я'пытаюсь получить некоторые данные из REST API HP Alm. Это работает довольно хорошо с небольшим скриптом curl - я получаю свои данные.
А вот с JavaScript, fetch и ES6 (более или менее), похоже, проблема посерьезнее. Я продолжаю получать это сообщение об ошибке:
Fetch API не может загрузить
. Ответ на запрос preflight не проходит прошел проверку контроля доступа: No 'Access-Control-Allow-Origin' header is присутствует на запрашиваемом ресурсе. 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 Plugin, но тогда я получаю другое сообщение об ошибке:
Значение заголовка 'Access-Control-Allow-Origin' в ответе не должно быть подстановочным символом '*', когда запрос'credentials mode is 'include'. Таким образом, Origin 'http://127.0.0.1:3000' не имеет права доступ. Режим учетных данных для запросов, инициированных функцией XMLHttpRequest, контролируется атрибутом withCredentials.
Этот ответ охватывает много тем, поэтому он разделен на три части:
Как использовать CORS-прокси, чтобы обойти "Нет заголовка Access-Control-Allow-Origin " проблемы.
Если вы не контролируете сервер, на который ваш внешний JavaScript-код отправляет запрос, и проблема с ответом от этого сервера заключается только в отсутствии необходимого заголовка Access-Control-Allow-Origin
, вы все равно можете заставить его работать, выполнив запрос через CORS-прокси. Чтобы показать, как это работает, сначала приведем код, который не использует CORS-прокси:
const url = "https://example.com"; // site that doesn’t send Access-Control-*
fetch(url)
.then(response => response.text())
.then(contents => console.log(contents))
.catch(() => console.log("Can’t access " + url + " response. Blocked by browser?"))
Причина, по которой блок catch
попадает туда, заключается в том, что браузер не позволяет этому коду получить доступ к ответу, который возвращается с https://example.com
. Причина, по которой браузер это делает, заключается в том, что в ответе отсутствует заголовок ответа Access-Control-Allow-Origin
.
А вот точно такой же пример, но только с добавлением CORS-прокси:
const proxyurl = "https://cors-anywhere.herokuapp.com/";
const url = "https://example.com"; // site that doesn’t send Access-Control-*
fetch(proxyurl + url) // https://cors-anywhere.herokuapp.com/https://example.com
.then(response => response.text())
.then(contents => console.log(contents))
.catch(() => console.log("Can’t access " + url + " response. Blocked by browser?"))
Примечание: Если https
https://example.com
.https://example.com
.Access-Control-Allow-Origin
к ответу.Access-Control-Allow-Origin
видит браузер.
Вы можете легко запустить свой собственный прокси, используя код с сайта https://github.com/Rob--W/cors-anywhere/.git clone https://github.com/Rob--W/cors-anywhere.git
cd cors-anywhere/
npm install
heroku create
git push heroku master
https://cors-anywhere.herokuapp.com
в URL-адресе вашего запроса вместо него будет указан URL-адрес вашего собственного экземпляра; например, https://cryptic-headland-94862.herokuapp.com/https://example.com.
Если вы попытаетесь использовать httpsOPTIONS
- потому что в этом случае прокси также отправляет обратно заголовки Access-Control-Allow-Headers
и Access-Control-Allow-Methods
, необходимые для успешной предварительной проверки.Как избежать предварительной проверки CORS.
Код в вопросе вызывает предварительную проверку CORS, поскольку отправляет заголовок Authorization
.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests
Даже без этого, заголовок Content-Type: application/json
также вызовет префлайт.
Что означает "preflight": прежде чем браузер попробует выполнить POST
в коде из вопроса, он сначала отправит серверу запрос OPTIONS
- чтобы определить, согласен ли сервер на получение кросс-оригинального POST
, включающего заголовки Authorization
и Content-Type: application/json
.
Это довольно хорошо работает с небольшим скриптом curl - я получаю свои данные. Чтобы правильно протестировать с помощью
curl
, вам нужно эмулировать предварительный запросOPTIONS
, который отправляет браузер:
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"
...с https://the.sign_in.url
, замененным на ваш фактический URL sign_in
.
Ответ, который браузер должен получить от этого запроса OPTIONS
, должен содержать такие заголовки, как:
Access-Control-Allow-Origin: http://127.0.0.1:3000
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type, Authorization
Если ответ OPTIONS
не содержит этих заголовков, то браузер остановится на этом и даже не попытается отправить запрос POST
. Кроме того, код состояния HTTP для ответа должен быть 2xx - обычно 200 или 204. Если это любой другой код статуса, браузер остановится прямо на месте.
Сервер, о котором идет речь, отвечает на запрос OPTIONS
кодом состояния 501, что, очевидно, означает, что он пытается указать на отсутствие поддержки запросов OPTIONS
. Другие серверы в этом случае обычно отвечают кодом состояния 405 "Метод не разрешен".
Таким образом, вы никогда не сможете делать POST
-запросы непосредственно к этому серверу из вашего внешнего JavaScript-кода, если сервер ответит на этот OPTIONS
-запрос кодом 405 или 501, или чем-либо другим, кроме 200 или 204, или если он не ответит необходимыми заголовками ответа.
Способ избежать срабатывания префлайта для случая, о котором идет речь в вопросе, следующий:
Authorization
, а вместо этого (например) полагается на данные аутентификации, встроенные в тело запроса POST
или в качестве параметра запросаPOST
имело медиа-тип Content-Type: application/json
, а вместо этого принял тело POST
как application/x-www-form-urlencoded
с параметром json
(или любым другим), значением которого являются данные JSON.Как решить проблему "Заголовок Access-Control-Allow-Origin не должен быть подстановочным символом ".
Я получаю другое сообщение об ошибке:
Значение заголовка 'Access-Control-Allow-Origin' в ответе не должно быть подстановочным символом '', когда запрос'режим учетных данных является 'include'. Таким образом, Origin 'http://127.0.0.1:3000' не разрешается. доступ. Режим учетных данных для запросов, инициированных XMLHttpRequest, контролируется атрибутом withCredentials. Для запроса, содержащего учетные данные, браузеры не позволят вашему фронтенд-коду JavaScript получить доступ к ответу, если значение заголовка ответа
Access-Control-Allow-Origin
равно `. Вместо этого значение в этом случае должно точно соответствовать происхождению вашего внешнего кода,
http://127.0.0.1:3000. Смотрите [*Кредитные запросы и подстановочные знаки*][1] в статье MDN HTTP контроль доступа (CORS). Если вы контролируете сервер, на который отправляете запрос, то распространенным способом решения этой проблемы является настройка сервера на получение значения заголовка запроса
Originи его эхо/отражение в значение заголовка ответа
Access-Control-Allow-Origin`. Например, в nginx:
add_header Access-Control-Allow-Origin $http_origin
Я использую Chrome. Я также пробовал использовать этот Chrome CORS Plugin. Этот CORS-плагин Chrome, по-видимому, просто-напросто вводит
Access-Control-Allow-Origin: *
в ответ, который видит браузер. Если бы плагин был умнее, он бы установил значение этого фальшивого заголовка ответаAccess-Control-Allow-Origin
на реальное происхождение вашего внешнего JavaScript-кода,http://127.0.0.1:3000
. Поэтому избегайте использования этого плагина даже для тестирования. Он просто отвлекает внимание. Если вы хотите проверить, какие ответы вы получаете от сервера без фильтрации браузером, лучше использоватьcurl -H
, как указано выше.Что касается фронтенд-кода JavaScript для запроса
fetch(...)
в вопросе:
headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');
Удалите эти строки. Заголовки Access-Control-Allow-*
являются заголовками ответа. Вы никогда не захотите отправлять их в запросе. Единственное, на что это может повлиять, - заставить браузер выполнить предварительную проверку.
Эта ошибка возникает, когда URL клиента и URL сервера не совпадают, включая номер порта. В этом случае вам необходимо включить в вашем сервисе функцию CORS - кросс-оригинальный обмен ресурсами.
Если вы используете REST-сервис Spring, то вы можете найти это в блоге Поддержка CORS в Spring Framework.
Если вы размещаете сервис на сервере Node.js, то
Остановите сервер Node.js.
npm install cors --save
.
Добавьте следующие строки в файл server.js
var cors = require('cors')
app.use(cors()) // Используйте это после объявления переменной
Проблема возникла из-за того, что вы добавили следующий код в виде заголовка request в интерфейсе:
headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');
Эти заголовки принадлежат ответу , а не запросу. Так что удалите их, включая строку: < br / >
headers.append('GET', 'POST', 'OPTIONS');
Ваш запрос имел «Content-Type: application / json», следовательно, вызвал то, что называется предполетным CORS. Это вызвало то, что браузер отправил запрос с методом OPTIONS. См. CORS preflight для получения подробной информации. & Лт; br / > Поэтому в вашем бэк-энде вы должны обработать этот предварительно выполненный запрос, вернув заголовки ответов, которые включают:
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
Конечно, фактический синтаксис зависит от языка программирования, который вы используете для своего бэкэнда.
В вашем интерфейсе это должно быть так:
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));
}
В моем случае я использую решение ниже
Front-end или Angular
post(
this.serverUrl, dataObjToPost,
{
headers: new HttpHeaders({
'Content-Type': 'application/json',
})
}
)
бэкэнд (я использую 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);
Просто мои два цента... относительно Как использовать прокси-сервер CORS, чтобы обойти проблемы «Нет заголовка« Access-Control-Allow-Origin »
Для тех из вас, кто работает с php на бэкэнде, развертывание «прокси-сервера CORS» так же просто, как:
создать файл с именем 'no-cors.php' со следующим содержимым:
$ URL = $ _GET ['url'] ; echo json_encode (file_get_contents ($ URL)) ; умереть();
на переднем конце сделайте что-нибудь вроде:
fetch ('https://example.com/no-cors.php' + '?url = '+ url) .then (response = > {* / Handle Response / *})
Уберите это:
credentials: 'include',
В моем случае веб-сервер предотвратил метод «ОПЦИИ»
Проверьте свой веб-сервер на предмет параметров метода
Я использую "вебтиер"
/www / webtier / домены / [доменное имя] /config/fmwconfig/components / OHS / VCWeb1 / httpd.conf
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{REQUEST_METHOD} ^OPTIONS
RewriteRule .* . [F]
</IfModule>
перейти на
<IfModule mod_rewrite.c>
RewriteEngine off
RewriteCond %{REQUEST_METHOD} ^OPTIONS
RewriteRule .* . [F]
</IfModule>
Использование 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
Я работал с Spring REST и решил добавить «Разрешенные методы» в 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");
}
};
}
Самое быстрое исправление, которое вы можете сделать, - это установить расширение Moesif CORS .
https://chrome.google.com/webstore/detail/moesif-orign-cors-changer/digfbfaphojjndkpccljibejjbppifbc?hl=en-US
После установки щелкните его в браузере, чтобы активировать расширение. Убедитесь, что метка значка идет от «выкл» «вкл» ; Затем обновите ваше приложение, и ваши запросы API теперь должны работать! Плагин определенно решает проблему. Однако это исправление относится только к вашей машине. В локальном развитии хорошо установить плагин, который поможет вам преодолеть ошибку.