I use google app script (where we usually use almost raw js, without libs and etc).
So I need to use proxy server (need dynamic-changing ip address).
But when i make request, proxy server calls back
This is a proxy server. Does not respond to non-proxy requests.
In common way, making http request in google app scrip seems like this:
function make_some_request() {
const url = 'https://www.google.com/';
var headers = {
"Content-Type" : "application/json; charset=utf-8",
}
var payload = []; // some data if we need post request
var options = {
"method" : "POST",
'headers' : headers,
'payload' : JSON.stringify(payload)
};
try {
var response = UrlFetchApp.fetch(url, options);
return JSON.parse(response);
} catch (error) {
log("make_some_request", "ERROR: " + error);
}
}
So, i can't understand what should i make with my request to use proxy server. How we make call through proxy server in common way (in raw HTTP). What headers or payload should i send to make this request a proxy-request?
P.S. as i know, google app script doesn't support another classes to make https requests. So all i have is almost raw HTTP.
I have created a demo using JavaScript for Flickr photo search API.
Now I am converting it to the AngularJs.
I have searched on internet and found below configuration.
Configuration:
myApp.config(function($httpProvider) {
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
});
Service:
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'}
});
}
});
Controller:
myApp.controller('flickrController', function($scope, dataService) {
$scope.data = null;
dataService.flickrPhotoSearch().then(function(dataResponse) {
$scope.data = dataResponse;
console.log($scope.data);
});
});
But still I got the same error.
Here are some links I tried:
XMLHttpRequest cannot load URL. Origin not allowed by Access-Control-Allow-Origin
http://goo.gl/JuS5B1
You don't. The server you are making the request to has to implement CORS to grant JavaScript from your website access. Your JavaScript can't grant itself permission to access another website.
I had a similar problem and for me it boiled down to adding the following HTTP headers at the response of the receiving end:
Access-Control-Allow-Headers: Content-Type
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Origin: *
You may prefer not to use the * at the end, but only the domainname of the host sending the data. Like *.example.com
But this is only feasible when you have access to the configuration of the server.
Try using the resource service to consume 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' });
});
Template:
<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>
This issue occurs because of web application security model policy that is Same Origin Policy Under the policy, a web browser permits scripts contained in a first web page to access data in a second web page, but only if both web pages have the same origin. That means requester must match the exact host, protocol, and port of requesting site.
We have multiple options to over come this CORS header issue.
Using Proxy - In this solution we will run a proxy such that when request goes through the proxy it will appear like it is some same origin.
If you are using the nodeJS you can use cors-anywhere to do the proxy stuff. https://www.npmjs.com/package/cors-anywhere.
Example:-
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 is a method for sending JSON data without worrying about cross-domain issues.It does not use the XMLHttpRequest object.It uses the <script> tag instead. https://www.w3schools.com/js/js_json_jsonp.asp
Server Side - On server side we need to enable cross-origin requests.
First we will get the Preflighted requests (OPTIONS) and we need to allow the request that is status code 200 (ok).
Preflighted requests first send an HTTP OPTIONS request header to the resource on the other domain, in order to determine whether the actual request is safe to send. Cross-site requests are preflighted like this since they may have implications to user data. In particular, a request is preflighted if it uses methods other than GET or POST. Also, if POST is used to send request data with a Content-Type other than application/x-www-form-urlencoded, multipart/form-data, or text/plain, e.g. if the POST request sends an XML payload to the server using application/xml or text/xml, then the request is preflighted.
It sets custom headers in the request (e.g. the request uses a header such as X-PINGOTHER)
If you are using the spring just adding the bellow code will resolves the issue.
Here I have disabled the csrf token that doesn't matter enable/disable according to your requirement.
#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("*");
}
};
}
}
If you are using the spring security use below code along with above code.
#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();
}
}
I encountered a similar problem like this, problem was with the backend . I was using node server(Express). I had a get request from the frontend(angular) as shown below
onGetUser(){
return this.http.get("http://localhost:3000/user").pipe(map(
(response:Response)=>{
const user =response.json();
return user;
}
))
}
But it gave the following error
This is the backend code written using express without the headers
app.get('/user',async(req,res)=>{
const user=await getuser();
res.send(user);
})
After adding a header to the method problem was solved
app.get('/user',async(req,res)=>{
res.header("Access-Control-Allow-Origin", "*");
const user=await getuser();
res.send(user);
})
You can get more details about Enabling CORS on Node JS
This answer outlines two ways to workaround APIs that don't support CORS:
Use a CORS Proxy
Use JSONP if the API Supports it
One workaround is to use a 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>
For more information, see
GitHub: CORS Anywhere
Use JSONP if the API supports it:
var url = "//api.ipify.org/";
var trust = $sce.trustAsResourceUrl(url);
$http.jsonp(trust,{params: {format:'jsonp'}})
.then(function(response) {
console.log(response);
$scope.response = response.data;
}).catch(function(response) {
console.log(response);
$scope.response = 'ERROR: ' + response.status;
})
The DEMO on PLNKR
For more information, see
AngularJS $http Service API Reference - $http.jsonp
Answered by myself.
CORS angular js + restEasy on POST
Well finally I came to this workaround:
The reason it worked with IE is because IE sends directly a POST instead of first a preflight request to ask for permission.
But I still don't know why the filter wasn't able to manage an OPTIONS request and sends by default headers that aren't described in the filter (seems like an override for that only case ... maybe a restEasy thing ...)
So I created an OPTIONS path in my rest service that rewrites the reponse and includes the headers in the response using response header
I'm still looking for the clean way to do it if anybody faced this before.
Apache/HTTPD tends to be around in most enterprises or if you're using Centos/etc at home. So, if you have that around, you can do a proxy very easily to add the necessary CORS headers.
I have a blog post on this here as I suffered with it quite a few times recently. But the important bit is just adding this to your /etc/httpd/conf/httpd.conf file and ensuring you are already doing "Listen 80":
<VirtualHost *:80>
<LocationMatch "/SomePath">
ProxyPass http://target-ip:8080/SomePath
Header add "Access-Control-Allow-Origin" "*"
</LocationMatch>
</VirtualHost>
This ensures that all requests to URLs under your-server-ip:80/SomePath route to http://target-ip:8080/SomePath (the API without CORS support) and that they return with the correct Access-Control-Allow-Origin header to allow them to work with your web-app.
Of course you can change the ports and target the whole server rather than SomePath if you like.
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);
we can enable CORS in the frontend by using the ngResourse module.
But most importantly, we should have this piece of code while making the ajax
request in the controller,
$scope.weatherAPI = $resource(YOUR API,
{callback: "JSON_CALLBACK"}, {get: {method: 'JSONP'}});
$scope.weatherResult = $scope.weatherAPI.get(YOUR REQUEST DATA, if any);
Also, you must add ngResourse CDN in the script part and add as a dependency
in the app module.
<script src="https://code.angularjs.org/1.2.16/angular-resource.js"></script>
Then use "ngResourse" in the app module dependency section
var routerApp = angular.module("routerApp", ["ui.router", 'ngResource']);
I'm getting the following error using AJAX to call an API on UPS
XMLHttpRequest cannot load https://wwwcie.ups.com/rest/Ship. Response to
preflight request doesn't pass access control check: No 'Access-Control-Allow-
Origin' header is present on the requested resource. Origin
'http://localhost:63786' is therefore not allowed access.
AJAX Call:
$.ajax({
url: "https://wwwcie.ups.com/rest/Ship",
type: "POST",
dataType: 'json',
crossDomain: true,
contentType: 'application/json',
data: JSON.stringify(message),
success: function (result) {
//code to execute on success
}
error: function (result) {
//code to execute on error
}
})
I have no control over the API server so I cannot modify the headers being sent back. I've tried JSONP, changing the headers I send, and a number of other solutions to no avail. I've read that making a server-side proxy could be a possible fit but I'm not sure how I would go about this. Any advice/code samples on possible solutions would be greatly appreciated. Thanks in advance.
What is to stop a malicious website from sending requests to your bank's web app and transferring all of your money? To prevent these types of shenanigans, if you're using a web browser, the server must explicitly state which remote origins are allowed to access a certain resource, if any.
If you need a key to access it, then CORS probably isn't enabled. You can always double check by looking at the response headers. See this:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
So as others have already mentioned, you can get around this by making the request from your own server (where the headers don't identify it as a browser and subject to CORS limitations), and proxy it to your client side app.
Assuming you're using Node/Express, something like this should work:
const express = require('express');
const app = express();
const myHeaders = new Headers();
const myInit = { method: 'GET',
headers: myHeaders,
mode: 'cors',
cache: 'default' };
app.get('/ups/stuff/stuff', (req, res) => {
fetch('/ups/api/stuff', myInit)
.then(response => response.json())
.then(json => res.json(json);
});
app.listen(3000);
The native fetch API is neat because you can use it on both client and server, and it supports promises like jQuery.
https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
I'm writing a website with AngularJS which communicates with an API on the server and provides some Info.
for Log in part I should send a http post request containing Email, Password and etc. It works fine on google Chrome and IE. I mean it sends the post request and gets a token. But in FireFox as I checked in Network, It sends an OPTION request and gets 200 but after that it does not send any post! hence my login would not disappear and I wont get any token.
what should I do for this situation?
App.config :
$httpProvider.defaults.withCredentials = true;
$httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8;';
$httpProvider.interceptors.push('httpRequestInterceptor');
Function in service which sends request :
this.loginEmail = function(f_email, f_pass, deviceModel, deviceOs) {
var data = $.param({
email: f_email,
password: f_pass,
device_model: deviceModel,
device_os: deviceOs
});
return $http({
method: "POST",
url: app.baseUrl + 'login_email/' + app.storeID + '/' + app.device_id,
data: data
}).success(function(response){
return response.status;
});
/*return $http.post(app.baseUrl + 'login_email/' + app.storeID + '/' + app.device_id, data).success(function(response){
return response.status;
}).error(function(response){
return response.status;
});*/
};
Server Credentials are true
CORS seems fine because I can do get request
EDIT:
Here's another thing that may be related to this problem:
in Chrome when I get logged in for get requests it sends the Token header
but for Post it doesn't
httpRequestInterceptor :
app.factory('httpRequestInterceptor', function ($cookieStore) {
return {
request: function (config) {
config.headers['Authorization'] = $cookieStore.get('Auth-Key');;
config.headers['Accept'] = 'application/json;odata=verbose';
return config;
}
};
});
The problem was caused by apache configurations.
before:
Access-Control-Allow-Headers: "authorization"
after:
Access-Control-Allow-Headers: "authorization, Content-type"
UPDATE :
On CORS requests if API requires some special headers like Auhtorization Token you must return all OPTIONS requests 200(ok!) if not the solution above would not work anyway.
Here's the code:
if($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
header( "HTTP/1.1 200 OK" );
exit();
}
UPDATE 2 :
This OPTIONS problem occurs in REST framework for Django! For OPTIONS it evaluates the request by pursing whole api if there was a problem in it, you'll get error even though you have required permissions for sending request!
Example:
Suppose that there's a url like api/profile which needs an Authorization header for responsing profile details. You want to send the Cross Domain request for getting it. You set the right headers and click! You'll get unauthorized error! Why? Because the pre flighted request(OPTIONS) does not include any special header and browser sends it to server, server with REST framework evaluates the OPTIONS request by checking the whole request(get request with authorization header) but OPTIONS doesn't have any authorization header so this request is unauthorized!
DEVELOPMENTAL SOLUTION :
This problem can be solved either by Client-Side or Back-End. Front-End developer can install following plugin on chrome:
Allow-Control-Allow-Origin: *
Back-End developer can install a package which enables CORS on Django Framework.
I am sending data in json format from javascript using XMLHttpRequest and receiving data at node.js file as following
client.js
$.ajax({
type: "POST",
dataType: 'json',
data: JSON.stringify(Idata),
url: AjaxURL,
success: function (result) {
return true;
}
});
server.js
var http = require('http');
console.log("server initialized");
var server = http.createServer(function (req, response) {
req.on('data', function (data) {
var d = JSON.parse(data);
console.log("data : " + d.OperationType);
});
req.on('end', function () {
response.end();
});
}).listen(3000);
Now i successfully got the value of operationtype but the at client browser this error is showing:
XMLHttpRequest cannot load http://localhost:3000/. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access.
The primary problem is that you are making a "GET" request. A data payload/HTTP request body cannot be uploaded with an XMLHttpRequest "GET" request. See the specification of XMLHttpRequest: "If stored method is GET act as if the data argument is null."
In order to send data, you should make a "POST" request, in this case:
xmlhttp.open("POST", AjaxURL, true);
In response to updated question:
For security reasons, your AJAX request will not be allowed to access your server hosted at localhost:3000 unless the AJAX request is initiated from a page served by localhost:3000 OR you tell your server to allow "cross-origin" requests. The latter can be accomplished by adding a line like this to your server:
response.setHeader("Access-Control-Allow-Origin", "*");
This sets a header that tells the browser to allow AJAX requests to localhost:3000 even if the request is initiated from a page that was not served by localhost:3000.
Please do the following:
In client.js, output the value Idata(using console.log) right before sending it.
Use the 'Network' tab in Chrome(or equivalent in your favorite browser) to check what is actually being sent.
In server.js, output the value data(using console.log) right after recieving it.
That will probably give you a clue as to where it went wrong, which will help you determine your next course of action. If you still don't know how to proceed, update the question and I will update my answer.
What I can say right now based on my (very lacking) knowledge of node.js, is that if the variable data is being treated as an object, store += data; is not a good idea, as that would mean you are trying to add an object to an (empty) string.
(Probably resulting in the object returning "[object Object]", or some such)