This question already has answers here:
Ways to circumvent the same-origin policy
(8 answers)
Closed 7 years ago.
I am trying to make an AJAX call to ajax.htm file. using web-worker. If it works fine, the data must keep populating at the given interval.
I dont get an error, and the get message seems to be working, but the data is not being populated on page. The message posted by the worker.js is not being listened to in the main page. Here is the code.
My webWorker.html file is as follows:
<!DOCTYPE html>
<html>
<head>
<title>Worker Sample</title>
<script type="text/javascript">
var worker = new Worker('worker.js');
// console.log(worker);
document.addEventListener("DOMContentLoaded",function(){
var result = document.querySelector('#result');
// console.log(result);
worker.addEventListener('message', function (event) {
console.log(event.data);
createElement('li', result,'',JSON.parse(event.data));
});
worker.addEventListener('error', function(err){
console.log("There was a problem",err);
});
worker.postMessage('start');
});
function createElement(elementType, parent, className, innerHTML, custom) {
var element = document.createElement(elementType);
if (parent) parent.appendChild(element);
if (className) element.className = className;
if (innerHTML) element.innerHTML = innerHTML;
if (typeof custom !== 'undefined') {
for (var prop in custom) {
element.setAttribute(prop, custom[prop]);
}
}
return element;
}
</script>
</head>
<body>
<div>
<ul id="result">Result</ul>
</div>
</body>
<html>
my worker.js is as follows:
/**
* Created by lakshmi on 7/22/15.
*/
self.addEventListener('message', function (e) {
if(e.data === 'start'){
setInterval(function () {
getData()
}, 1000);
}
function getData() {
var xhr = new XMLHttpRequest();
xhr.open('GET','ajaxcontent.htm');
xhr.withCredentials = true;
// xhr.setRequestHeader("Content-Type", "text/event-stream");
xhr.addEventListener('readyStateChange',function(){
if(xhr.readyState === 4){
self.postMessage(xhr.responseText);
}
});
xhr.send();
}
});
ajaxcontent.htm
content from external page
CORS error means, that you are doing request to other domain, and other domain did not allow cross domain request.Try to do request to your domain.Other domain can allow some headers or some request method types (POST,DELETE,GET,PUT), can allow access from all domains or from some domains.
If you are disagree with my answer, explain why.
Related
Is it possible to perform an action before every http request sent upon clicking an a-href tag? I would like to perform the action before every referred http request as well (eg requests for images/scripts in the DOM). Thanks!
It can be achieved for every HTTP ajax request.
Note : Dummy requests in examples are made to HTTP Bin.
JAVASCRIPT:
References : JS XMLHttpRequest
(function init()
{
XMLHttpRequest.prototype._open = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function(method, url, async, user, password){
initialChanges();
this._open(method, url, async, user, password);
};
})();
function initialChanges()
{
alert("Making a Javascript ajax request.");
}
function makeRequestViaXHR()
{
var req = new XMLHttpRequest();
req.open("GET","https://httpbin.org/get",false,null,null);
req.onreadystatechange=function(){
if(req.readyState === 4)
{
if(req.status === 200)
{
console.log(req.responseText);
}
else
{
console.log("Request Failed");
}
}
};
req.send();
}
<button onclick="makeRequestViaXHR()">Make a dummy ajax request via Javascript</button>
JQUERY:
References : jQuery ajax, jQuery .ajaxSend
(function init()
{
$(document).ajaxSend(function(event,xhr,settings){
alert("Making a jQuery ajax request.");
});
})();
function makeRequestViaJquery()
{
$.ajax({
url:"https://httpbin.org/get",
method:"GET",
async:true,
success:function(response){
console.log(response);
},
error:function(error){
console.log(error);
}
});
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button onclick="makeRequestViaJquery()">Make a dummy ajax request via jQuery</button>
In case of navigating to other pages, downloading files or mail addresses via <a> tag, execute the method on click using addEventListener.
References : HTML Element Subinterfaces
document.addEventListener("click", function(event){
var elem = event.target;
if(elem instanceof HTMLAnchorElement) //For <a> tag
{
executeThis();
}
});
function executeThis()
{
alert("Element is clicked");
}
Click this anchor element
Download Image
Scripts execute only after the DOM is loaded. If some function need to be executed before loading the images, you need to add the method with a script tag before every img element. Refer this for more info.
So on subdomain of my domain I have a html file, for example called file.html, which also includes <script src="https://example.com/script.js"> in itself.
Then, this script.js has some listeners connected with this html, and also the function to send messages to parent, which look as follows:
v.sendMessageToParent = function (message) {
var jsonMessage = {
action: message
};
var win = window.frames.target;
win.postMessage(jsonMessage, '*');
};
v.sendActionMessageToParent = function (action) {
var jsonMessage = {
action: 'action',
type: action
};
var win = window.frames.target;
win.postMessage(jsonMessage, '*');
};
Then, on another domain I have an iframe, which src is file.html.
This another domain also has some <script src="example.com/main.js">, and I need this main.js to listen to messages sent from script.js.
In main.js I have this code:
if (window.addEventListener) {
window.addEventListener("message", messageHandler);
} else {
window.attachEvent("onmessage", messageHandler);
}
function messageHandler(event) {
console.log(event.data);
}
But I don't get anything. No JS, domain or other errors are shown, just silence in console.
Where am I wrong?
Probably you forgot to name your iframe "target":
<iframe src="http://target.com" name="target">
<script>
var win = window.frames.target;
win.postMessage("message", *);
</script>
I am a newbie as far as web development is concerned and even more so with Google App Scripts and OAuth2.0. Having said that, I have researched enough and also tried several tricks, but still can't get past this issue.
I borrowed sample from here:
Google Developers - Client API Library
Then created an Apps Script project with an index.html file with code from that page. I also created a project on the developer console, created a client ID, API key and turned on the required API support. I also made the required changes to the sample to reflect the new client ID and API key.
The index.html page is served from HTML Service with SandBox Mode set to IFRAME. If I load the URL in a browser window (say using incognito mode) and click "Authorize" button, it opens the Google sign-in window. But after signing in, it opens two new tabs with messages
Please close this window
and the original browser window shows no change.
The JavaScript console shows error messages like these:
Unsafe JavaScript attempt to initiate navigation for frame with URL ''
from frame with URL
https://accounts.google.com/o/oauth2/postmessageRelay?parent=https%3A%2F%2F…6lxdpyio6iqy-script.googleusercontent.com#rpctoken=288384029&forcesecure=1.
The frame attempting navigation is sandboxed, and is therefore
disallowed from navigating its ancestors.
From the messages, it seems its an effect of using IFRAME and some sort of security feature is preventing the callback being delivered to the original window. If I reload the original window, things work OK. But that's not what I would ideally like.
How do I work around this issue? Its a very simple project and I can provide source code if that helps.
Thanks,
Pavan
Edit: Here is the sample code I'm trying. You would need to have your client ID and API Key and also set JS origins in the Google Console for things to work:
Code.gs
function doGet(e) {
return HtmlService.createHtmlOutputFromFile('index').setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
index.html
<!--
Copyright (c) 2011 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License"); you may not
use this file except in compliance with the License. You may obtain a copy of
the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations under
the License.
To run this sample, replace YOUR API KEY with your application's API key.
It can be found at https://code.google.com/apis/console/?api=plus under API Access.
Activate the Google+ service at https://code.google.com/apis/console/ under Services
-->
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8' />
</head>
<body>
<!--Add a button for the user to click to initiate auth sequence -->
<button id="authorize-button" style="visibility: hidden">Authorize</button>
<script type="text/javascript">
// Enter a client ID for a web application from the Google Developer Console.
// The provided clientId will only work if the sample is run directly from
// https://google-api-javascript-client.googlecode.com/hg/samples/authSample.html
// In your Developer Console project, add a JavaScript origin that corresponds to the domain
// where you will be running the script.
var clientId = 'YOUR_CLIENT_ID';
// Enter the API key from the Google Develoepr Console - to handle any unauthenticated
// requests in the code.
// The provided key works for this sample only when run from
// https://google-api-javascript-client.googlecode.com/hg/samples/authSample.html
// To use in your own application, replace this API key with your own.
var apiKey = 'YOUR API KEY';
// To enter one or more authentication scopes, refer to the documentation for the API.
var scopes = 'https://www.googleapis.com/auth/plus.me';
// Use a button to handle authentication the first time.
function handleClientLoad() {
gapi.client.setApiKey(apiKey);
window.setTimeout(checkAuth,1);
}
function checkAuth() {
gapi.auth.authorize({client_id: clientId, scope: scopes, immediate: true, response_type: 'token'}, handleAuthResult);
}
function handleAuthResult(authResult) {
var authorizeButton = document.getElementById('authorize-button');
if (authResult && !authResult.error) {
authorizeButton.style.visibility = 'hidden';
makeApiCall();
} else {
authorizeButton.style.visibility = '';
authorizeButton.onclick = handleAuthClick;
}
}
function handleAuthClick(event) {
gapi.auth.authorize({client_id: clientId, scope: scopes, immediate: false, response_type: 'token'}, handleAuthResult);
return false;
}
// Load the API and make an API call. Display the results on the screen.
function makeApiCall() {
gapi.client.load('plus', 'v1', function() {
var request = gapi.client.plus.people.get({
'userId': 'me'
});
request.execute(function(resp) {
var heading = document.createElement('h4');
var image = document.createElement('img');
image.src = resp.image.url;
heading.appendChild(image);
heading.appendChild(document.createTextNode(resp.displayName));
heading.appendChild(document.createTextNode(resp.emails[0].value));
document.getElementById('content').appendChild(heading);
});
});
}
</script>
<script src="https://apis.google.com/js/client.js?onload=handleClientLoad"></script>
<div id="content"></div>
<p>Retrieves your profile name using the Google Plus API.</p>
</body>
</html>
found a solution... not nice but works oO:
the trick is to remove the oauth2relay iframes before the auth window is closed. after the window is closed you have to add the frames again and do a immediate request, if that works the user authorized the app.
be careful:
this script does not check if the user meanwhile is logged out or the token is expired, as long as the webapp window is open the same token is used.
Code.js:
function doGet(e) {
return HtmlService.createTemplateFromFile('Index').evaluate().setTitle(formSettings.title).setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
function include(file) {
return HtmlService.createHtmlOutputFromFile(file).getContent();
}
function doPost(meta) {
if (!meta || !meta.auth) {
throw new Error('not authorized');
return;
}
var auth = JSON.parse(UrlFetchApp.fetch('https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=' + meta.auth.access_token, { muteHttpExceptions: true }).getContentText());
if (auth.error || !auth.email) {
throw new Error('not authorized');
return;
}
if (typeof this[meta.method + '_'] == 'function') {
return this[meta.method + '_'](auth.email, meta.data);
}
throw new Error('unknown method');
}
function test_(email, data) {
return email;
}
Index.html:
<html>
<head>
<?!= include('JavaScript'); ?>
</head>
<body>
<div class="content-wrapper">
</div>
</body>
</html>
Javascript.html:
<script type='text/javascript' src="//ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script type='text/javascript' src="//apis.google.com/js/client.js?onload=apiLoaded" async></script>
<script type='text/javascript'>
var clientId = '*************-********************************.apps.googleusercontent.com';
var scopes = ['https://www.googleapis.com/auth/plus.me', 'https://www.googleapis.com/auth/userinfo.email'];
var loaded = false;
var auth = null;
function apiLoaded() {
loaded = true;
login();
}
window._open = window.open;
window._windows = [];
window.open = function(url) {
var w = window._open.apply(window,arguments);
window._windows.push(w);
return w;
}
function login(step) {
step || (step = 0);
if (!loaded) {
return;
}
gapi.auth.authorize({client_id: clientId, scope: scopes, immediate: (step <= 0 || step >= 2) }, function(authResult) {
if (authResult) {
if (authResult.error) {
if (authResult.error == 'immediate_failed' && authResult.error_subtype == 'access_denied' && step <= 0) {
var interval = setInterval(function() {
var $ifr = $('iframe');//[id^=oauth2relay]');
if (!window._windows.length) {
clearInterval(interval);
return;
}
if ($ifr.length) {
clearInterval(interval);
$ifr.detach();
var w = window._windows.pop();
if (w) {
var interval2 = setInterval(function() {
if (w.closed) {
clearInterval(interval2);
$('body').append($ifr);
login(2);
}
});
} else {
$('body').append($ifr);
}
}
},500);
login(1);
} else if (authResult.error == 'immediate_failed' && authResult.error_subtype == 'access_denied' && step >= 2) {
//user canceled auth
} else {
//error
}
} else {
auth = authResult;
doPost('test', { some: 'data' }, 'test');
}
} else {
//error
}
});
}
function test() {
console.log(arguments);
}
//with this method you can do a post request to webapp server
function doPost(method, data, callbackName) {
data || (data = {});
google.script.run.withSuccessHandler(onSuccess).withFailureHandler(onError).withUserObject({ callback: callbackName }).doPost({ method: method, data: data, auth: auth });
}
function onSuccess(data, meta) {
if (typeof window[meta.callback] == 'function') {
window[meta.callback](null, data);
}
}
function onError(err, meta) {
if (typeof window[meta.callback] == 'function') {
window[meta.callback](err);
}
}
</script>
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 9 years ago.
I have JS code which works on IE browser.
But it doesn't work in Chrome and Mozilla.
What should be changed to make it work on these browsers?
<html>
<head>
<script type="text/javascript">
function readFile(url) {
pageRequest = new XMLHttpRequest()
pageRequest.open("GET", url, false);
pageRequest.send(null);
return pageRequest.responseText;
}
</script>
</head>
<body>
<script type="text/javascript">
var txt = readFile("?GameID=5&from=0&num=50000");
document.write(txt);
</script>
</body>
</html>
function readFile(url) {
var request = new XMLHttpRequest();
request.open("GET", url, false);
request.send();
return request;
}
var request = readFile("http://? GameID=5&from=0&num=50000");
request.onload = function() {
document.write(request.responseText);
};
this code doesnt work neither in IE nor in Chrome))
any other ideas?
This occurs because of Cross-Origin Resource Sharing, click here for more details. You need to set the Access-Control-Allow-Origin header on server and define the domains that have permissions to access the resource. I tested your code in a server with Internet Explorer and got the same error.
You're having async problems. If the HTTP request didn't finish yet, you won't be able to access request.responseText. This might work in some browsers because of pure chance. So we have to attach an onload event listener.
Try this code:
function readFile(url) {
var request = new XMLHttpRequest();
request.open("GET", url, false);
request.send();
return request;
}
var request = readFile("http://example.com/displayScore.php?GameID=5&from=0&num=50000");
request.onload = function() {
document.write(request.responseText);
};
You could also pass readFile a second parameter that is a function like this instead of returning the whole object:
function readFile(url, onload) {
//load code goes here...
if (typeof onload == "function") {
request.onload = function(){
onload(request),
};
}
}
readFile("url", function(e){
document.write(e.responseText);
});
I have a link: Hello.
When someone clicks the link I'd like to check via JavaScript if the page the href-attribute points to exists or not. If the page exists the browser redirects to that page ("www.example.com" in this example) but if the page doesn't exist the browser should redirect to another URL.
It depends on whether the page exists on the same domain or not. If you're trying to determine if a page on an external domain exists, it won't work – browser security prevents cross-domain calls (the same-origin policy).
If it is on the same domain however, you can use jQuery like Buh Buh suggested. Although I'd recommend doing a HEAD-request instead of the GET-request the default $.ajax() method does – the $.ajax() method will download the entire page. Doing a HEAD request will only return the headers and indicate whether the page exists (response codes 200 - 299) or not (response codes 400 - 499). Example:
$.ajax({
type: 'HEAD',
url: 'http://yoursite.com/page.html',
success: function() {
// page exists
},
error: function() {
// page does not exist
}
});
See also: http://api.jquery.com/jQuery.ajax/
A pretty good work around is to proxy. If you don't have access to a server side you can use YQL. Visit: http://developer.yahoo.com/yql/console/
From there you can do something like: select * from htmlstring where url="http://google.com". You can use the "REST query" they have on that page as a starting point for your code.
Here's some code that would accept a full URL and use YQL to detect if that page exists:
function isURLReal(fullyQualifiedURL) {
var URL = encodeURIComponent(fullyQualifiedURL),
dfd = $.Deferred(),
checkURLPromise = $.getJSON('http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20htmlstring%20where%20url%3D%22' + URL + '%22&format=json');
checkURLPromise
.done(function(response) {
// results should be null if the page 404s or the domain doesn't work
if (response.query.results) {
dfd.resolve(true);
} else {
dfd.reject(false);
}
})
.fail(function() {
dfd.reject('failed');
});
return dfd.promise();
}
// usage
isURLReal('http://google.com')
.done(function(result) {
// yes, or request succeded
})
.fail(function(result) {
// no, or request failed
});
Update August 2nd, 2017
It looks like Yahoo deprecated "select * from html", although "select * from htmlstring" does work.
Based on the documentation for XMLHttpRequest:
function returnStatus(req, status) {
//console.log(req);
if(status == 200) {
console.log("The url is available");
// send an event
}
else {
console.log("The url returned status code " + status);
// send a different event
}
}
function fetchStatus(address) {
var client = new XMLHttpRequest();
client.onreadystatechange = function() {
// in case of network errors this might not give reliable results
if(this.readyState == 4)
returnStatus(this, this.status);
}
client.open("HEAD", address);
client.send();
}
fetchStatus("/");
This will however only work for URLs within the same domain as the current URL. Do you want to be able to ping external services? If so, you could create a simple script on the server which does your job for you, and use javascript to call it.
If it is in the same domain, you can make a head request with the xmlhttprequest object [ajax] and check the status code.
If it is in another domain, make an xmlhttprequest to the server and have it make the call to see if it is up.
why not just create a custom 404 handler on the web server? this is probably the more "good-bear" way to do this.
$.ajax({
url: "http://something/whatever.docx",
method: "HEAD",
statusCode: {
404: function () {
alert('not found');
},
200: function() {
alert("foundfile exists");
}
}
});
If you are happy to use jQuery you could do something like this.
When the page loads make an ajax call for each link. Then just replace the href of all the links which fail.
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
<script type="text/javascript">
<!--
$.fn.checkPageExists = function(defaultUrl){
$.each(this, function(){
var $link = $(this);
$.ajax({
url: $link.attr("href"),
error: function(){
$link.attr("href", defaultUrl);
}
});
});
};
$(document).ready(function(){
$("a").checkPageExists("default.html");
});
//-->
</script>
You won't be able to use an ajax call to ping the website because of same-origin policy.
The best way to do it is to use an image and if you know the website you are calling has a favicon or some sort of icon to grab, you can just use an html image tag and use the onerror event.
Example:
function pingImgOnWebsite(url) {
var img = document.createElement('img');
img.style.visibility = 'hidden';
img.style.position = 'fixed';
img.src = url;
img.onerror = continueBtn; // What to do on error function
document.body.appendChild(img);
}
Another way to do this is is with PHP.
You could add
<?php
if (file_exists('/index.php'))
{
$url = '/index.php';
} else {
$url = '/notindex.php';
}
?>
And then
<a href="<?php echo $url; ?>Link</a>