1.需要一个manifest.json 文件
2.需要一个background.js 文件
3.需要一个popup.js 文件 popup.html 文件
4.其他页面 比如oss.html 和oss.js 文件, 以及utils/oss.js 请求方法
manifest.json:
{
"manifest_version": 3,
"name": "OSS上传插件",
"version": "1.0",
"description": "【上传数据,调用接口,显示并复制结果】【自动查询Pushy资源包hash值】",
"permissions": ["storage"],
"host_permissions": [
"https://******.cn/*",
"https://******.seakoi.net/*", 告诉插件允许跨域的地址
"https://at.alicdn.com/*"
],
"action": {
"default_popup": "popup.html"
},
"web_accessible_resources": [
{
"resources": [
"assets/pushStyles.css",
"panels/push/index.html",
"panels/push/index.js"
],
"matches": ["<all_urls>"]
}
],
"background": {
"service_worker": "background.js",
"type": "module"
}
}
background.js : 发送接收浏览器发送的请求,匹配后端接口请求,将后端请求结果作为浏览器请求结果并返回
import { login, fetchUploadFile } from "./api/oss.js";
const LOGIN_API_URL = "https://update.react-native.cn/api/user/login";
const AUTO_LOGIN_CREDENTIALS = {
email: "service@seakoi.cn",
pwd: "d69b63258378b191b0fdb7aa5a68a9e3",
};
async function checkLoginStatus() {
const result = await chrome.storage.local.get(["token"]);
return !!result.token;
}
async function getStoredData() {
const result = await chrome.storage.local.get(["token", "userInfo"]);
return {
token: result.token || null,
userInfo: result.userInfo || null,
};
}
async function performLogin(credentials) {
try {
if (!credentials || !credentials.email || !credentials.pwd) {
throw new Error("缺少登录凭据");
}
const response = await fetch(LOGIN_API_URL, {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
body: JSON.stringify({
email: credentials.email,
pwd: credentials.pwd,
}),
credentials: "omit",
});
if (!response.ok) {
const errorText = await response.text().catch(() => "");
console.error("登录API响应:", {
status: response.status,
statusText: response.statusText,
headers: Object.fromEntries(response.headers.entries()),
body: errorText,
});
throw new Error(
`登录失败: ${response.status} ${errorText || response.statusText}`
);
}
const data = await response.json();
if (data.token && data.info) {
await chrome.storage.local.set({
token: data.token,
userInfo: {
email: data.info.email,
name: data.info.name,
},
});
return {
success: true,
data: {
token: data.token,
userInfo: {
email: data.info.email,
name: data.info.name,
},
},
};
} else {
throw new Error("登录响应数据格式错误");
}
} catch (error) {
console.error("登录错误:", error);
return {
success: false,
error: error.message || "登录失败,请检查网络连接",
};
}
}
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
(async () => {
try {
console.log("收到的消息1111", message.body);
switch (message.action) {
case "uploadUrlChrome":
const res1 = await fetchUploadFile(message.body);
console.log("收到的消息3333", message);
sendResponse({ success: true, data: res1 }); (将后端请求结果作为浏览器请求结果返回,给到浏览器发送请求的方法)
case "marktingLogin":
const res = await login(message.body);
console.log("收到的消息2222", message);
sendResponse({ success: true, data: res });
break;
case "checkStatus":
const isLoggedIn = await checkLoginStatus();
sendResponse({ success: true, isLoggedIn });
break;
case "autoLogin":
const autoLoginResult = await performLogin(AUTO_LOGIN_CREDENTIALS);
sendResponse(autoLoginResult);
break;
case "login":
const loginResult = await performLogin(message.credentials);
sendResponse(loginResult);
break;
case "getUserInfo":
const storedData = await getStoredData();
sendResponse({
success: true,
token: storedData.token,
userInfo: storedData.userInfo,
});
break;
default:
sendResponse({ success: false, error: "未知的操作" });
}
} catch (error) {
console.error("消息处理错误:", error);
sendResponse({ success: false, error: error.message });
}
})();
return true;
});
popop.js (结合了所有的其他页面)
const tabsData = [
{ id: "oss", title: "OSS上传", folder: "panels/oss" },
{ id: "other", title: "其他面板", folder: "panels/other" },
{ id: "push", title: "Push登录状态", folder: "panels/push" },
];
const tabsContainer = document.getElementById("tabsContainer");
const contentsContainer = document.getElementById("contentsContainer");
tabsData.forEach((tab, index) => {
const tabBtn = document.createElement("div");
tabBtn.className = "tab" + (index === 0 ? " active" : "");
tabBtn.dataset.tab = tab.id;
tabBtn.innerText = tab.title;
tabsContainer.appendChild(tabBtn);
const contentDiv = document.createElement("div");
contentDiv.className = "tab-content" + (index === 0 ? " active" : "");
contentDiv.id = tab.id;
fetch(`${tab.folder}/index.html`)
.then((res) => res.text())
.then((html) => {
contentDiv.innerHTML = html;
const script = document.createElement("script");
script.src = `${tab.folder}/index.js`;
script.type = "module";
contentDiv.appendChild(script);
})
.catch((err) => (contentDiv.innerHTML = "<p>加载失败</p>"));
contentsContainer.appendChild(contentDiv);
});
function setupTabs() {
const tabs = document.querySelectorAll(".tab");
const contents = document.querySelectorAll(".tab-content");
tabs.forEach((tab) => {
tab.addEventListener("click", () => {
const targetId = tab.dataset.tab;
tabs.forEach((t) => t.classList.remove("active"));
tab.classList.add("active");
contents.forEach((c) => c.classList.remove("active"));
const targetContent = document.getElementById(targetId);
if (targetContent) targetContent.classList.add("active");
});
});
}
setupTabs();
utils/oss.js请求方法:
import request from "../api/request.js";
export async function apiRequest({
action = "marktingLogin",
method = "GET",
url,
body = null,
}) {
return new Promise((resolve, reject) => {
chrome.runtime.sendMessage(
{
action,
method,
url,
body,
},
(response) => {
if (!response) {
reject(new Error("No response from background"));
return;
}
if (response.success) {
resolve(response.data);
} else {
reject(new Error(response.error || "Request failed"));
}
}
);
});
}
export const loadUser = async (body) => {
console.log("加载用户信息");
try {
const data = await apiRequest({
method: "post",
url: "/api/base/login",
body,
});
console.log("用户信息:", data);
} catch (err) {
console.error("请求失败:", err?.message);
}
};
export const uploadUrlChrome = async (body) => {
console.log("加载用户信息");
try {
const data = await apiRequest({
method: "post",
action: "uploadUrlChrome",
body,
});
console.log("用户信息:", data);
return data;
} catch (err) {
console.error("请求失败:", err?.message);
}
};
export const login = async (credentials) => {
try {
const res = await request.post("/api/base/login", credentials);
return res;
} catch (err) {
console.error("登录失败:", err.message);
throw err;
}
};
export const getFont = async ({ url }) => {
try {
const res = await request.get(
"/font",
{ url },
{ responseType: "blob" }
);
return res;
} catch (err) {
console.error("请求阿里font失败", err.message);
throw err;
}
};
export const uploadFont = async ({ data }) => {
try {
const res = await request.post(
"/api/fileUploadAndDownload/upload?fileType=system",
{ file: data },
{
headers: {
"Content-Type": "multipart/form-data",
},
}
);
return res;
} catch (err) {
console.error("请求阿里font失败", err.message);
throw err;
}
};
export const fetchUploadFile = async (data) => {
if (!data?.url) return;
try {
console.log(data, "dsadfadffsf");
const font = await getFont({ url: data?.url });
const formData = new FormData();
console.log(font, "fdsfsffffffffffff11111111");
const fileName = "downloaded_font.css";
formData.append("file", font, fileName);
const uploadResult = await uploadFont({ data: formData });
console.log(formData, font, uploadResult, "sadfasdfsafs22222222222");
if (uploadResult?.code === 0) {
return uploadResult?.data?.file?.url ?? "";
}
throw new Error("上传接口报错");
} catch (error) {
console.error("Error processing file:", error);
throw new Error(error);
}
};
oss.html || oss.js
# **在oss.js 中 我们可以通过点击,触发浏览器请求的方法,匹配到后端接口后,执行后端请求。最后通过浏览器请求接口最后返回到是后端请求的结果。**
import { loadUser, uploadUrlChrome } from "../../api/oss.js";
console.log("OSS 面板 JS 加载完成");
const LOGIN_STATE_KEY = "oss_is_logged_in";
const loginView = document.getElementById("loginView");
const ossUploadView = document.getElementById("ossUploadView");
const loginSubmitBtn = document.getElementById("loginSubmitBtn");
const logoutBtn = document.getElementById("logoutBtn");
const loginUsernameInput = document.getElementById("loginUsername");
const loginPasswordInput = document.getElementById("loginPassword");
const renderView = () => {
const isLoggedIn = localStorage.getItem(LOGIN_STATE_KEY) === "true";
if (isLoggedIn) {
loginView.classList.add("view-hidden");
ossUploadView.classList.remove("view-hidden");
console.log("当前视图: OSS 上传面板");
} else {
loginView.classList.remove("view-hidden");
ossUploadView.classList.add("view-hidden");
console.log("当前视图: 登录面板");
}
};
const handleLogin = async () => {
const username = loginUsernameInput.value.trim();
const password = loginPasswordInput.value;
const loginObject = {
checkoutSecret: true,
deviceUniqueId: "",
internalDeviceId: "",
loginAppVersion: "",
loginDeviceType: "Mac/Chrome",
loginIsApp: 0,
openCaptcha: false,
password: "123456",
username: "13345678953",
};
console.log(`尝试使用 ${username} 登录...`);
await loadUser({
...loginObject,
username: "17688710001",
password: "123456",
});
const success = true;
if (success) {
localStorage.setItem(LOGIN_STATE_KEY, "true");
renderView();
loginPasswordInput.value = "";
alert(`欢迎回来,${username}!`);
} else {
alert("登录失败,请检查账号和密码。");
}
};
const handleLogout = () => {
localStorage.removeItem(LOGIN_STATE_KEY);
renderView();
alert("您已安全退出。");
};
if (loginSubmitBtn) {
loginSubmitBtn.addEventListener("click", handleLogin);
}
if (logoutBtn) {
logoutBtn.addEventListener("click", handleLogout);
}
renderView();
const uploadBtn = document.getElementById("uploadBtn");
if (uploadBtn) {
uploadBtn.addEventListener("click", async () => {
const url = "https://at.alicdn.com/t/c/font_4997520_o6cupx6t3v.js";
if (url) {
document.getElementById("newUrl").value = `正在上传 ${url} ...`;
const resultUrl = await uploadUrlChrome({ url });
console.log("开始上传:", url);
document.getElementById("newUrl").value = resultUrl;
} else {
document.getElementById("newUrl").value = `请输入有效的地址!`;
}
});
}