Hen*_*son 5 google-apps-script
我运行Google Apps脚本,将文件上传到用户的Google云端硬盘文件中:
function doGet(e) {
var blob = UrlFetchApp.fetch(e.parameters.url).getBlob();
DriveApp.createFile(blob);
return HtmlService.createHtmlOutput("DONE!");
}
Run Code Online (Sandbox Code Playgroud)
我的网站加载了一个弹出窗口,该窗口使用该代码运行Google Apps脚本.工作良好.
现在,我怎么沟通回到我的网站,他们的用户已成功上传的文件?在,如何与用户运行的服务器进行通信doGet()?`
某些类型的response处理必须存在?
完整的工作代码(在JSBin上测试):
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.js"></script>
</head>
<body>
<div class="google-upload" data-url="https://calibre-ebook.com/downloads/demos/demo.docx">
<span style="background-color: #ddd">Upload</span>
</div>
<script>
$(function() {
$(".google-upload").click(function() {
var url = "https://script.google.com/macros/s/AKfycbwsuIcO5R86Xgv4E1k1ZtgtfKaENaKq2ZfsLGWZ4aqR0d9WBYc/exec"; // Please input the URL here.
var withQuery = url + "?url=";
window.open(withQuery + $('.google-upload').attr("data-url"), "_blank", "width=600,height=600,scrollbars=1");
});
});
</script>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)
因此,为了澄清,我想要一种方法来确定用户是否已成功上传文件.就像是:
request.execute(function(response) {
if (response.code == 'uploaded') {
// uploaded, do stuff
} else {
// you get the idea...
}
});
Run Code Online (Sandbox Code Playgroud)
为此提供完整解决方案的赏金.
HtmlService您可以使用jQuery的$.getJSON方法传递数据并从doGet函数中检索数据,而不是返回对象ContentService.Google Apps脚本不接受CORS,因此使用JSONP是从脚本获取数据的最佳方式.有关更多信息,请参阅此帖
为清楚起见,我拆分了HTML和脚本.没有HTML从您的原始示例更改.
Code.gs
function doGet(e) {
var returnValue;
// Set the callback param. See https://stackoverflow.com/questions/29525860/
var callback = e.parameter.callback;
// Get the file and create it in Drive
try {
var blob = UrlFetchApp.fetch(e.parameters.url).getBlob();
DriveApp.createFile(blob);
// If successful, return okay
// Structure this JSON however you want. Parsing happens on the client side.
returnValue = {status: 'okay'};
} catch(e) {
Logger.log(e);
// If a failure, return error message to the client
returnValue = {status: e.message}
}
// Returning as JSONP allows for crossorigin requests
return ContentService.createTextOutput(callback +'(' + JSON.stringify(returnValue) + ')').setMimeType(ContentService.MimeType.JAVASCRIPT);
}
Run Code Online (Sandbox Code Playgroud)
客户端JS
$(function() {
$(".google-upload").click(function() {
var appUrl = "https://script.google.com/macros/s/AKfycbyUvgKdhubzlpYmO3Marv7iFOZwJNJZaZrFTXCksxtl2kqW7vg/exec";
var query = appUrl + "?url=";
var popupUrl = query + $('.google-upload').attr("data-url") + "&callback=?";
console.log(popupUrl)
// Open this to start authentication.
// If already authenticated, the window will close on its own.
var popup = window.open(popupUrl, "_blank", "width=600,height=600,scrollbars=1");
$.getJSON(popupUrl, function(returnValue) {
// Log the value from the script
console.log(returnValue.status);
if(returnValue.status == "okay") {
// Do stuff, like notify the user, close the window
popup.close();
$("#result").html("Document successfully uploaded");
} else {
$("#result").html(returnValue);
}
})
});
});
Run Code Online (Sandbox Code Playgroud)
您可以通过在data-url参数中传递空字符串来测试错误消息.该消息在控制台以及用户的页面中返回.
上述解决方案存在控制授权流程的问题.在与Drive工程师进行研究和交流之后(请参阅此处的主题),我将其重新编写为基于Apps Script API的自托管示例,并将项目作为API可执行文件而非Apps Script Web App运行.这将允许您[run](https://developers.google.com/apps-script/api/reference/rest/v1/scripts/run)在Apps Script Web应用程序之外访问该方法.
按照适用于JavaScript的Google Apps脚本API说明进行操作.Apps脚本项目应该是独立的(不链接到文档)并作为API可执行文件发布.您需要打开云控制台并创建OAuth凭据和API密钥.
您可以在计算机上使用Python服务器.我使用Node JS服务器,http-server但您也可以在线直播并从那里进行测试.您需要在云端控制台中将源列入白名单.
由于这是自托管的,因此您需要一个纯HTML页面,OAuth2通过JavaScript 通过API 授权用户.这是首选,因为它保持用户登录,允许对脚本进行多次API调用而无需重新授权.以下代码适用于此应用程序,并使用Google快速入门指南中的授权流程.
的index.html
<body>
<!--Add buttons to initiate auth sequence and sign out-->
<button id="authorize-button" style="display: none;">Authorize</button>
<button id="signout-button" style="display: none;">Sign Out</button>
<button onclick="uploadDoc()" style="margin: 10px;" id="google-upload" data-url="https://calibre-ebook.com/downloads/demos/demo.docx">Upload doc</button>
<pre id="content"></pre>
</body>
Run Code Online (Sandbox Code Playgroud)
index.js
// Client ID and API key from the Developer Console
var CLIENT_ID = 'YOUR_CLIENT_ID';
var API_KEY = 'YOUR_API_KEY';
var SCRIPT_ID = 'YOUR_SCRIPT_ID';
// Array of API discovery doc URLs for APIs used by the quickstart
var DISCOVERY_DOCS = ["https://script.googleapis.com/$discovery/rest?version=v1"];
// Authorization scopes required by the API; multiple scopes can be
// included, separated by spaces.
var SCOPES = 'https://www.googleapis.com/auth/drive https://www.googleapis.com/auth/script.external_request';
var authorizeButton = document.getElementById('authorize-button');
var signoutButton = document.getElementById('signout-button');
var uploadButton = document.getElementById('google-upload');
var docUrl = uploadButton.getAttribute('data-url').value;
// Set the global variable for user authentication
var isAuth = false;
/**
* On load, called to load the auth2 library and API client library.
*/
function handleClientLoad() {
gapi.load('client:auth2', initClient);
}
/**
* Initializes the API client library and sets up sign-in state
* listeners.
*/
function initClient() {
gapi.client.init({
apiKey: API_KEY,
clientId: CLIENT_ID,
discoveryDocs: DISCOVERY_DOCS,
scope: SCOPES
}).then(function () {
// Listen for sign-in state changes.
gapi.auth2.getAuthInstance().isSignedIn.listen(updateSigninStatus);
// Handle the initial sign-in state.
updateSigninStatus(gapi.auth2.getAuthInstance().isSignedIn.get());
authorizeButton.onclick = handleAuthClick;
signoutButton.onclick = handleSignoutClick;
// uploadButton.onclick = uploadDoc;
});
}
/**
* Called when the Upload button is clicked. Reset the
* global variable to `true` and upload the document.
* Thanks to @JackBrown for the logic.
*/
function updateSigninStatus(isSignedIn) {
if (isSignedIn && !isAuth) {
authorizeButton.style.display = 'none';
signoutButton.style.display = 'block';
uploadButton.style.display = 'block'
uploadButton.onclick = uploadDoc;
} else if (isSignedIn && isAuth) {
authorizeButton.style.display = 'none';
signoutButton.style.display = 'block';
uploadButton.style.display = 'block';
uploadDoc();
} else {
authorizeButton.style.display = 'block';
signoutButton.style.display = 'none';
uploadButton.style.display = 'none';
isAuth = false;
}
}
/**
* Sign in the user upon button click.
*/
function handleAuthClick(event) {
gapi.auth2.getAuthInstance().signIn();
isAuth = true; // Update the global variable
}
/**
* Sign out the user upon button click.
*/
function handleSignoutClick(event) {
gapi.auth2.getAuthInstance().signOut();
isAuth = false; // update the global variable
}
/**
* Append a pre element to the body containing the given message
* as its text node. Used to display the results of the API call.
*
* @param {string} message Text to be placed in pre element.
*/
function appendPre(message) {
var pre = document.getElementById('content');
var textContent = document.createTextNode(message + '\n');
pre.appendChild(textContent);
}
/**
* Handle the login if signed out, return a Promise
* to call the upload Docs function after signin.
**/
function uploadDoc() {
console.log("clicked!")
var docUrl = document.getElementById('google-upload').getAttribute('data-url');
gapi.client.script.scripts.run({
'scriptId':SCRIPT_ID,
'function':'uploadDoc',
'parameters': [ docUrl ]
}).then(function(resp) {
var result = resp.result;
if(result.error && result.error.status) {
// Error before the script was Called
appendPre('Error calling API');
appendPre(JSON.parse(result, null, 2));
} else if(result.error) {
// The API executed, but the script returned an error.
// Extract the first (and only) set of error details.
// The values of this object are the script's 'errorMessage' and
// 'errorType', and an array of stack trace elements.
var error = result.error.details[0];
appendPre('Script error message: ' + error.errorMessage);
if (error.scriptStackTraceElements) {
// There may not be a stacktrace if the script didn't start
// executing.
appendPre('Script error stacktrace:');
for (var i = 0; i < error.scriptStackTraceElements.length; i++) {
var trace = error.scriptStackTraceElements[i];
appendPre('\t' + trace.function + ':' + trace.lineNumber);
}
}
} else {
// The structure of the result will depend upon what the Apps
// Script function returns. Here, the function returns an Apps
// Script Object with String keys and values, and so the result
// is treated as a JavaScript object (folderSet).
console.log(resp.result)
var msg = resp.result.response.result;
appendPre(msg);
// do more stuff with the response code
}
})
}
Run Code Online (Sandbox Code Playgroud)
Apps脚本代码不需要进行太多修改.ContentService我们可以返回客户端使用的普通JSON对象,而不是返回使用.
function uploadDoc(e) {
Logger.log(e);
var returnValue = {};
// Set the callback URL. See https://stackoverflow.com/questions/29525860/
Logger.log("Uploading the document...");
try {
// Get the file and create it in Drive
var blob = UrlFetchApp.fetch(e).getBlob();
DriveApp.createFile(blob);
// If successful, return okay
var msg = "The document was successfully uploaded!";
return msg;
} catch(e) {
Logger.log(e);
// If a failure, return error message to the client
return e.message
}
}
Run Code Online (Sandbox Code Playgroud)
我很难将CodePen列入白名单,所以我使用上面的代码在我自己的网站上安全地托管了一个示例.随意检查源代码并查看实时Apps脚本项目.
请注意,在您添加或更改Apps脚本项目中的范围时,用户需要重新授权.
| 归档时间: |
|
| 查看次数: |
560 次 |
| 最近记录: |