Ответ 1
Нет. Сервер, на который вы делаете запрос, должен внедрить CORS для предоставления JavaScript с вашего сайта. Ваш JavaScript не может предоставить себе разрешение на доступ к другому сайту.
Я создал демо-версию с использованием JavaScript для API поиска фотографий Flickr. Теперь я конвертирую его в AngularJs. Я искал в Интернете и нашел ниже конфигурацию.
Конфигурация:
myApp.config(function($httpProvider) {
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
});
Услуги:
myApp.service('dataService', function($http) {
delete $http.defaults.headers.common['X-Requested-With'];
this.flickrPhotoSearch = function() {
return $http({
method: 'GET',
url: 'http://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=3f807259749363aaa29c76012fa93945&tags=india&format=json&callback=?',
dataType: 'jsonp',
headers: {'Authorization': 'Token token=xxxxYYYYZzzz'}
});
}
});
Контроллер:
myApp.controller('flickrController', function($scope, dataService) {
$scope.data = null;
dataService.flickrPhotoSearch().then(function(dataResponse) {
$scope.data = dataResponse;
console.log($scope.data);
});
});
Но все-таки я получил ту же ошибку. Вот некоторые ссылки, которые я пробовал:
XMLHttpRequest не может загрузить URL. Происхождение не разрешено Access-Control-Allow-Origin
http://samurails.com/tutorial/cors-with-angular-js-and-sinatra/
EDIT:
Я создал прокси-сервер в node.js по предложению @Quentin:
var http = require('http');
var url = require('url');
var fs = require('fs');
var server;
server = http.createServer(function (req, res) {
// your normal server code
var path = url.parse(req.url).pathname;
fs.readFile(__dirname + path, function (err, data) {
if (err) {
return send404(res);
}
res.writeHead(200, {'Content-Type':path == 'json.js' ? 'text/javascript' : 'text/html'});
res.write(data, 'utf8');
res.end();
});
}),
server.listen(8001);
//using express to load customizes static files
var express = require("express"),
app = express();
app.all("/api/*", function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With");
res.header("Access-Control-Allow-Methods", "GET, PUT, POST");
return next();
});
app.use("/js", express.static(__dirname + '/js'));
app.listen(3001);
Финальное редактирование
Я удалил заголовок авторизации
headers: {'Authorization': 'Token token=xxxxYYYYZzzz'}
и он работает нормально. У меня есть то, что я хотел. Спасибо всем за участие в этом вопросе
Нет. Сервер, на который вы делаете запрос, должен внедрить CORS для предоставления JavaScript с вашего сайта. Ваш JavaScript не может предоставить себе разрешение на доступ к другому сайту.
У меня была аналогичная проблема, и для меня это сводилось к добавлению следующих HTTP-заголовков в ответе конца :
Access-Control-Allow-Headers: Content-Type
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Origin: *
Вы можете не использовать *
в конце, а только имя домена хоста, отправляющего данные. Как *.example.com
Но это возможно только при наличии доступа к конфигурации сервера.
Попробуйте использовать службу ресурсов для использования flickr jsonp:
var MyApp = angular.module('MyApp', ['ng', 'ngResource']);
MyApp.factory('flickrPhotos', function ($resource) {
return $resource('http://api.flickr.com/services/feeds/photos_public.gne', { format: 'json', jsoncallback: 'JSON_CALLBACK' }, { 'load': { 'method': 'JSONP' } });
});
MyApp.directive('masonry', function ($parse) {
return {
restrict: 'AC',
link: function (scope, elem, attrs) {
elem.masonry({ itemSelector: '.masonry-item', columnWidth: $parse(attrs.masonry)(scope) });
}
};
});
MyApp.directive('masonryItem', function () {
return {
restrict: 'AC',
link: function (scope, elem, attrs) {
elem.imagesLoaded(function () {
elem.parents('.masonry').masonry('reload');
});
}
};
});
MyApp.controller('MasonryCtrl', function ($scope, flickrPhotos) {
$scope.photos = flickrPhotos.load({ tags: 'dogs' });
});
Шаблон:
<div class="masonry: 240;" ng-controller="MasonryCtrl">
<div class="masonry-item" ng-repeat="item in photos.items">
<img ng-src="{{ item.media.m }}" />
</div>
</div>
Эта проблема возникает из-за политики модели безопасности веб-приложения, которая является той же самой политикой происхождения. В соответствии с этой политикой веб-браузер разрешает сценариям, содержащимся на первой веб-странице, доступ к данным на второй веб-странице, но только если обе веб-страницы имеют одинаковое происхождение. Это означает, что запрашивающая сторона должна соответствовать точному хосту, протоколу и порту запрашивающего сайта.
У нас есть несколько вариантов решения этой проблемы с заголовком CORS.
Использование прокси- сервера. В этом решении мы запустим прокси-сервер таким образом, чтобы при прохождении запроса через прокси-сервер он выглядел так, как будто он какого-то происхождения. Если вы используете nodeJS вы можете использовать CORS в любом месте, чтобы сделать прокси вещи. https://www.npmjs.com/package/cors-anywhere.
Пример: -
var host = process.env.HOST || '0.0.0.0';
var port = process.env.PORT || 8080;
var cors_proxy = require('cors-anywhere');
cors_proxy.createServer({
originWhitelist: [], // Allow all origins
requireHeader: ['origin', 'x-requested-with'],
removeHeaders: ['cookie', 'cookie2']
}).listen(port, host, function() {
console.log('Running CORS Anywhere on ' + host + ':' + port);
});
JSONP - JSONP - это метод отправки данных JSON, не беспокоясь о междоменных проблемах. Он не использует объект XMLHttpRequest. Вместо него используется <script>
. https://www.w3schools.com/js/js_json_jsonp.asp
На стороне сервера - на стороне сервера мы должны включить запросы кросс-происхождения. Сначала мы получим Предварительно просвеченные запросы (ОПЦИИ), и нам нужно разрешить запрос с кодом состояния 200 (хорошо).
Предварительно выданные запросы сначала отправляют заголовок запроса HTTP OPTIONS ресурсу в другом домене, чтобы определить, безопасен ли фактический запрос для отправки. Межсайтовые запросы предварительно просматриваются следующим образом, так как они могут иметь значение для пользовательских данных. В частности, запрос предварительно выдан, если он использует методы, отличные от GET или POST. Кроме того, если POST используется для отправки данных запроса с Content-Type, отличным от application/x-www-form-urlencoded, multipart/form-data или text/plain, например, если запрос POST отправляет полезную нагрузку XML на сервер используя application/xml или text/xml, запрос предварительно просвечивается. Он устанавливает пользовательские заголовки в запросе (например, запрос использует заголовок, такой как X-PINGOTHER)
Если вы используете пружину, просто добавьте приведенный ниже код, чтобы решить проблему. Здесь я отключил токен csrf, который не имеет значения, включить/отключить в соответствии с вашими требованиями.
@SpringBootApplication
public class SupplierServicesApplication {
public static void main(String[] args) {
SpringApplication.run(SupplierServicesApplication.class, args);
}
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("*");
}
};
}
}
Если вы используете систему безопасности Spring, используйте приведенный ниже код вместе с приведенным выше кодом.
@Configuration
@EnableWebSecurity
public class SupplierSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests().antMatchers(HttpMethod.OPTIONS, "/**").permitAll().antMatchers("/**").authenticated().and()
.httpBasic();
}
}
Я столкнулся с подобной проблемой, как эта, проблема была с бэкэндом. Я использовал узел сервера (Express). У меня был запрос get от внешнего интерфейса (угловой), как показано ниже
onGetUser(){
return this.http.get("http://localhost:3000/user").pipe(map(
(response:Response)=>{
const user =response.json();
return user;
}
))
}
Это внутренний код, написанный с использованием Express без заголовков.
app.get('/user',async(req,res)=>{
const user=await getuser();
res.send(user);
})
После добавления заголовка в метод проблема была решена
app.get('/user',async(req,res)=>{
res.header("Access-Control-Allow-Origin", "*");
const user=await getuser();
res.send(user);
})
Вы можете получить более подробную информацию о включении CORS на Node JS
Отвечал сам.
CORS angular js + restEasy на POST
Ну, наконец, я пришел к этому обходному пути: Причина, по которой он работал с IE, заключается в том, что IE отправляет непосредственно POST вместо первого запроса предпросмотра, чтобы запросить разрешение. Но я до сих пор не знаю, почему фильтр не смог управлять запросом OPTIONS и отправляет по умолчанию заголовки, которые не описаны в фильтре (похоже, это переопределение для этого только случая... может быть, остальная вещь..)
Итак, я создал путь OPTIONS в моем сервисе отдыха, который перезаписывает ответ и включает заголовки в ответе с использованием заголовка ответа
Я все еще ищу чистый способ сделать это, если кто-то столкнулся с этим раньше.
Apache/HTTPD обычно присутствует на большинстве предприятий или если вы используете Centos/и т.д. Дома. Так что, если у вас это есть, вы можете очень легко создать прокси, чтобы добавить необходимые заголовки CORS.
У меня есть запись в блоге на этом здесь, как я страдал с ним довольно много раз в последнее время. Но важный момент - это просто добавить это в ваш файл /etc/httpd/conf/httpd.conf и убедиться, что вы уже выполняете "Listen 80":
<VirtualHost *:80>
<LocationMatch "/SomePath">
ProxyPass http://target-ip:8080/SomePath
Header add "Access-Control-Allow-Origin" "*"
</LocationMatch>
</VirtualHost>
Это гарантирует, что все запросы к URL-адресам в вашем-server-ip: 80/SomePath направляются на http://target-ip: 8080/SomePath (API без поддержки CORS) и что они возвращаются с правильным Access-Control-Allow- Исходный заголовок, позволяющий им работать с вашим веб-приложением.
Конечно, вы можете изменить порты и настроить таргетинг на весь сервер, а не SomePath, если хотите.
var result=[];
var app = angular.module('app', []);
app.controller('myCtrl', function ($scope, $http) {
var url="";// your request url
var request={};// your request parameters
var headers = {
// 'Authorization': 'Basic ' + btoa(username + ":" + password),
'Access-Control-Allow-Origin': true,
'Content-Type': 'application/json; charset=utf-8',
"X-Requested-With": "XMLHttpRequest"
}
$http.post(url, request, {
headers
})
.then(function Success(response) {
result.push(response.data);
$scope.Data = result;
},
function Error(response) {
result.push(response.data);
$scope.Data = result;
console.log(response.statusText + " " + response.status)
});
});
And also add following code in your WebApiConfig file
var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);
мы можем включить CORS во внешнем интерфейсе с помощью модуля ngResourse. Но самое главное, мы должны иметь этот кусок кода при выполнении запроса AJAX в контроллере,
$scope.weatherAPI = $resource(YOUR API,
{callback: "JSON_CALLBACK"}, {get: {method: 'JSONP'}});
$scope.weatherResult = $scope.weatherAPI.get(YOUR REQUEST DATA, if any);
Кроме того, вы должны добавить CDN ngResourse в части скрипта и добавить в качестве зависимости в модуль приложения.
<script src="https://code.angularjs.org/1.2.16/angular-resource.js"></script>
Затем используйте "ngResourse" в разделе зависимостей модуля приложения
var routerApp = angular.module("routerApp", ["ui.router", 'ngResource']);
В этом ответе изложены два способа обхода API, которые не поддерживают CORS:
Одним из способов решения этой проблемы является использование CORS PROXY:
angular.module("app",[])
.run(function($rootScope,$http) {
var proxy = "//cors-anywhere.herokuapp.com";
var url = "http://api.ipify.org/?format=json";
$http.get(proxy +'/'+ url)
.then(function(response) {
$rootScope.response = response.data;
}).catch(function(response) {
$rootScope.response = 'ERROR: ' + response.status;
})
})
<script src="//unpkg.com/angular/angular.js"></script>
<body ng-app="app">
Response = {{response}}
</body>