![](/img/trans.png)
[英]Special Characters to HTML for API POST method in Javascript - Google Script
[英]GitHub Rest Api SHA of file that contains special characters
主要問題
此代碼有效,但areReallyEqual
不是必需的。 事實上,不包含特殊字符(“ñ”、“é”、“à”等)的文件沒有必要,所以:我的所有文件除了其中的 2 個。
if (internalFileTextSha !== repositoryFile.sha) {
// The sha might not be equal due to special characters in the text ("ñ", "é", "à", etc)... doing a second check...
const remoteFileText = this._gitHubApi.fetchGitHubGetUrl(repositoryFile.download_url).getContentText();
const remoteFileTextSha = GitHubCrypto.getSha(remoteFileText);
const areReallyEqual = remoteFileTextSha === internalFileTextSha;
if(!areReallyEqual) {
// The file has been modified, creating a new commit with the updated file...
this._gitHubApi.commitUpdatedFile(repositoryName, repositoryFile, internalFile.source);
} else {
// The second check determined that both files were equal
}
}
更多細節
internalFile
來自這里:
/**
* @typedef {Object} InternalFile
* @property {string} id - The ID of the internal file.
* @property {string} name - The name of the internal file.
* @property {string} type - The type of the internal file.
* @property {string} source - The source code of the internal file.
*/
/**
* Gets all the internal files of a Google Apps Script file.
*
* @returns {InternalFile[]} An array of objects.
*/
static getScriptInternalFiles(file) {
// Check that the file is a Google Apps Script file
if (file.getMimeType() == 'application/vnd.google-apps.script') {
// Get the script content as a string
const fileId = file.getId();
const params = {
headers: {
Authorization: 'Bearer ' + ScriptApp.getOAuthToken(),
'Accept-Charset': 'utf-8'
},
followRedirects: true,
muteHttpExceptions: true,
};
const url =
'https://script.google.com/feeds/download/export?id='
+ fileId
+ '&format=json';
const response = UrlFetchApp.fetch(url, params);
const json = JSON.parse(response);
return json.files;
} else {
throw new Error("The file is not a Google Apps Script file.");
}
}
...而remoteFile
來自這里:
/**
* @typedef {Object} RepositoryFile
* @property {string} name - The name of the file.
* @property {string} path - The file path in the repository.
* @property {string} sha - The SHA hash of the file.
* @property {Number} size - The size of the file in bytes.
* @property {string} url - The URL of the file's contents.
* @property {string} html_url - The URL to the file's page on the repository website.
* @property {string} git_url - The URL to the file's git contents.
* @property {string} download_url - The URL to download the file.
* @property {string} type - The type of the file, usually "file".
*/
/**
* Gets all the internal files of a Google Apps Script file.
*
* @returns {RepositoryFile[]} An array of objects.
*/
listFilesInRepository(repositoryName) {
let repositoryFiles = [];
try {
const options = {
headers: {
...this._authorizationHeader,
},
};
const response = UrlFetchApp.fetch(`${this._buildRepositoryUrl(repositoryName)}/contents`, options);
repositoryFiles = JSON.parse(response);
} catch(e) {
const errorMessage = GitHubApi._getErrorMessage(e);
if(errorMessage === 'This repository is empty.') {
// do nothing
} else {
// unknown error
throw e;
}
}
return repositoryFiles;
}
...和 SHA 計算:
class GitHubCrypto {
/**
* @param {string} fileContent
* @returns {string} SHA1 hash string
*/
static getSha(fileContent) {
// GitHub is computing the sum of `blob <length>\x00<contents>`, where `length` is the length in bytes of the content string and `\x00` is a single null byte.
// For the Sha1 implementation, see: www.movable-type.co.uk/scripts/sha1.html
const sha = Sha1.hash('blob ' + fileContent.length + '\x00' + fileContent);
return sha;
}
}
我相信你的目標如下。
ñèàü
的值中檢索430f370909821443112064cd149a4bebd271bfc4
的 has 值。在這種情況下,下面的示例腳本怎么樣?
function myFunction() {
const fileContent = 'ñèàü'; // This is from your comment.
const value = 'blob ' + fileContent.length + '\x00' + fileContent;
const bytes = Utilities.computeDigest(Utilities.DigestAlgorithm.SHA_1, value, Utilities.Charset.UTF_8);
const res = bytes.map(byte => ('0' + (byte & 0xFF).toString(16)).slice(-2)).join('');
console.log(res); // 430f370909821443112064cd149a4bebd271bfc4
}
430f370909821443112064cd149a4bebd271bfc4
。aaaa
直接使用時像const res = Utilities.computeDigest(Utilities.DigestAlgorithm.SHA_1, "aaaa", Utilities.Charset.UTF_8).map(byte => ('0' + (byte & 0xFF).toString(16)).slice(-2)).join('')
,得到70c881d4a26984ddce795f6f71817c9cf4480e79
。我終於找到了問題......問題出在“字節長度”:
GitHub 正在計算blob <length>\x00<contents>
的總和,其中length
是內容字符串的字節長度,而\x00
是單個 null 字節。
當沒有特殊字符時, lengthInBytes == inputStr.length
,但當有特殊字符時,這不再是真的:
// For the Sha1 implementation, see: www.movable-type.co.uk/scripts/sha1.html
function simpleShaTest1() {
const fileContent = 'ñèàü';
const expectedSha = '56c9357fcf2589619880e1978deb8365454ece11';
const sha = Sha1.hash('blob ' + byteLength(fileContent) + '\x00' + fileContent);
const areEqual = (sha === expectedSha); // true
}
function simpleShaTest2() {
const fileContent = 'aaa';
const expectedSha = '7c4a013e52c76442ab80ee5572399a30373600a2';
const sha = Sha1.hash('blob ' + lengthInUtf8Bytes(fileContent) + '\x00' + fileContent);
const areEqual = (sha === expectedSha); // true
}
function lengthInUtf8Bytes(str) {
// Matches only the 10.. bytes that are non-initial characters in a multi-byte sequence.
var m = encodeURIComponent(str).match(/%[89ABab]/g);
// `m` is `null` when there are no special characters, thus returning `m.length`
return str.length + (m ? m.length : 0);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.