在 Tampermonkey 的使用者腳本中發出 API 請求很容易會出現 CORS 錯誤:
原因是因為伺服器沒有明確允許,所以被瀏覽器阻擋。不過這不是今天要探討的重點,在 Tampermonkey 有個內建函式可以很輕鬆的繞過這個限制,輕鬆的呼叫 API,就是使用 GM_xmlhttpRequest
發送 API 示範:
只是一發送就會出現錯誤:
GM_xmlhttpRequest is not defined?所以沒有這個函式可以使用?!
後來把整個文件看完,才發現原來在 Tampermonkey 中要使用 GM_, unsafeWindow, window 等功能強大的函式需要事先宣告權限,才可以使用:
並且在 UserScript 區塊中還要使用 @connect 定義允許的網域,不然會出現以下訊息,使用者需要手動點擊同意:
定義的時候可以定義多個允許的網域,也可以直接使用 * 表示全部允許
該如何取得 API 的回應呢?直接看下面的完整範例:
參考資料:
Tampermonkey - Documentation
translate.google.com.tw/:1 Access to XMLHttpRequest at 'http://localhost:3001/api' from origin 'https://translate.google.com.tw' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
原因是因為伺服器沒有明確允許,所以被瀏覽器阻擋。不過這不是今天要探討的重點,在 Tampermonkey 有個內建函式可以很輕鬆的繞過這個限制,輕鬆的呼叫 API,就是使用 GM_xmlhttpRequest
發送 API 示範:
const url = 'http://localhost:3001/api';
const data = {
a: 1,
b: 2,
}
GM_xmlhttpRequest({
method: "POST", // GET, HEAD, POST
url: url,
headers: {"Content-Type": "application/json"},
data: JSON.stringify(data),
timeout: 10000, // 毫秒
});
只是一發送就會出現錯誤:
userscript.html?name=New-Userscript.user.js&id=1d838e34-c86d-4cb8-9d8e-dd77722f9eff:25 Uncaught (in promise) ReferenceError: GM_xmlhttpRequest is not defined
at userscript.html?name=New-Userscript.user.js&id=1d838e34-c86d-4cb8-9d8e-dd77722f9eff:25:5
at Object.<anonymous> (userscript.html?name=New-Userscript.user.js&id=1d838e34-c86d-4cb8-9d8e-dd77722f9eff:32:3)
at Gt (<anonymous>:9:89)
at userscript.html?name=New-Userscript.user.js&id=1d838e34-c86d-4cb8-9d8e-dd77722f9eff:1:90
at window.__f__lq8euq2z.kyn (userscript.html?name=New-Userscript.user.js&id=1d838e34-c86d-4cb8-9d8e-dd77722f9eff:1:318)
at Gt (<anonymous>:9:89)
at o (<anonymous>:78:23)
at <anonymous>:80:411
at f (<anonymous>:74:452)
GM_xmlhttpRequest is not defined?所以沒有這個函式可以使用?!
後來把整個文件看完,才發現原來在 Tampermonkey 中要使用 GM_, unsafeWindow, window 等功能強大的函式需要事先宣告權限,才可以使用:
// ==UserScript==
// @name API Test
// @namespace http://ruyut.com/
// @version 2023-12-16
// @description 發送 API 示範
// @author Ruyut
// @match https://translate.google.com.tw/*
// @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
// @grant GM_xmlhttpRequest
// @connect localhost
// ==/UserScript==
(function () {
'use strict';
const data = {
a: 1,
b: 2,
}
const url = 'http://localhost:3001/api';
GM_xmlhttpRequest({
method: "POST", // GET, HEAD, POST
url: url,
headers: {"Content-Type": "application/json"},
data: JSON.stringify(data),
timeout: 10000, // 毫秒
});
})();
並且在 UserScript 區塊中還要使用 @connect 定義允許的網域,不然會出現以下訊息,使用者需要手動點擊同意:
定義的時候可以定義多個允許的網域,也可以直接使用 * 表示全部允許
// @connect localhost
// @connect example.com
// @connect *
該如何取得 API 的回應呢?直接看下面的完整範例:
// ==UserScript==
// @name API Test
// @namespace http://ruyut.com/
// @version 2023-12-16
// @description 發送 API 示範
// @author Ruyut
// @match https://translate.google.com.tw/*
// @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
// @grant GM_xmlhttpRequest
// @connect localhost
// ==/UserScript==
(function () {
'use strict';
const url = 'http://localhost:3001/api';
const data = {
a: 1,
b: 2,
}
GM_xmlhttpRequest({
method: "POST", // GET, HEAD, POST
url: url,
headers: {"Content-Type": "application/json"},
data: JSON.stringify(data),
timeout: 10000, // 毫秒
onload: function (response) { // 取得回應
console.log(`status:`, response.status); // 200
console.log(`result:`, response.responseText); // 回應 Body
},
});
})();
參考資料:
Tampermonkey - Documentation
留言
張貼留言
如果有任何問題、建議、想說的話或文章題目推薦,都歡迎留言或來信: a@ruyut.com