本帖最后由 268296 于 2025-7-24 15:18 编辑
博客上的教程地址: https://www.cveoy.top/t/topic/qFMo
中国站( aliyun.com )免费领ESA: http://s.tb.cn/e6.0FuRjs (官方链接非aff)
国际站( alibabacloud.com )免费领ESA: http://s.tb.cn/e6.0vy7ie (官方链接非aff)
在 https://esa.console.aliyun.com/edge/function/list 创建一个边缘函数
代码换为以下代码
• 'use strict'
•
• const ASSET_URL = 'https://www.cveoy.top/'
• const JS_VER = 10
• const MAX_RETRY = 1
•
• /** [url=home.php?mod=space&uid=26679]@Type[/url] {RequestInit} */
• const PREFLIGHT_INIT = {
• status: 204,
• headers: new Headers({
• 'access-control-allow-origin': '*',
• 'access-control-allow-methods': 'GET,POST,PUT,PATCH,TRACE,DELETE,HEAD,OPTIONS',
• 'access-control-max-age': '1728000',
• }),
• }
•
• /** 工具函数:生成响应 */
• function makeRes(body, status = 200, headers = {}) {
• headers['--ver'] = JS_VER
• headers['access-control-allow-origin'] = '*'
• return new Response(body, { status, headers })
• }
•
• /** 工具函数:解析 URL */
• function newUrl(urlStr) {
• try {
• return new URL(urlStr)
• } catch (err) {
• return null
• }
• }
•
• /** 入口函数:模块方式导出 */
• export default {
• async fetch(req, env, ctx) {
• return fetchHandler(req).catch(err =>
• makeRes('cfworker error:\n' + err.stack, 502)
• )
• }
• }
•
• /** 主处理函数 */
• async function fetchHandler(req) {
• const urlStr = req.url
• const urlObj = new URL(urlStr)
• const path = urlObj.href.substr(urlObj.origin.length)
•
• // 强制 HTTPS 跳转
• if (urlObj.protocol === 'http:') {
• urlObj.protocol = 'https:'
• return makeRes('', 301, {
• 'strict-transport-security': 'max-age=99999999; includeSubDomains; preload',
• 'location': urlObj.href,
• })
• }
•
• // 代理请求
• if (path.startsWith('/http/')) {
• return httpHandler(req, path.substr(6))
• }
•
• // 特殊路径处理
• switch (path) {
• case '/http':
• return makeRes('请更新到最新版本!')
• case '/ws':
• return makeRes('not support', 400)
• case '/works':
• return makeRes('it works')
• default:
• return fetch(ASSET_URL + path)
• }
• }
•
• /** HTTP 代理处理逻辑 */
• function httpHandler(req, pathname) {
• const reqHdrRaw = req.headers
• if (reqHdrRaw.has('x-jsproxy')) {
• return Response.error()
• }
•
• if (
• req.method === 'OPTIONS' &&
• reqHdrRaw.has('access-control-request-headers')
• ) {
• return new Response(null, PREFLIGHT_INIT)
• }
•
• let acehOld = false
• let rawSvr = ''
• let rawLen = ''
• let rawEtag = ''
•
• const reqHdrNew = new Headers(reqHdrRaw)
• reqHdrNew.set('x-jsproxy', '1')
•
• const refer = reqHdrNew.get('referer') || ''
• const query = refer.includes('?') ? refer.split('?')[1] : ''
• if (!query) {
• return makeRes('missing params', 403)
• }
•
• const param = new URLSearchParams(query)
• for (const [k, v] of param.entries()) {
• if (k.startsWith('--')) {
• switch (k.slice(2)) {
• case 'aceh':
• acehOld = true
• break
• case 'raw-info':
• [rawSvr, rawLen, rawEtag] = v.split('|')
• break
• }
• } else {
• if (v) {
• reqHdrNew.set(k, v)
• } else {
• reqHdrNew.delete(k)
• }
• }
• }
•
• if (!param.has('referer')) {
• reqHdrNew.delete('referer')
• }
•
• const urlStr = pathname.replace(/^(https?):\/+/, '$1://')
• const urlObj = newUrl(urlStr)
• if (!urlObj) {
• return makeRes('invalid proxy url: ' + urlStr, 403)
• }
•
• const reqInit = {
• method: req.method,
• headers: reqHdrNew,
• redirect: 'manual',
• body: req.method === 'POST' ? req.body : undefined,
• }
•
• return proxy(urlObj, reqInit, acehOld, rawLen, 0)
• }
•
• /** 发起代理请求 */
• async function proxy(urlObj, reqInit, acehOld, rawLen, retryTimes) {
• const res = await fetch(urlObj.href, reqInit)
• const resHdrOld = res.headers
• const resHdrNew = new Headers(resHdrOld)
•
• let expose = '*'
•
• for (const [k, v] of resHdrOld.entries()) {
• if (
• k === 'access-control-allow-origin' ||
• k === 'access-control-expose-headers' ||
• k === 'location' ||
• k === 'set-cookie'
• ) {
• const x = '--' + k
• resHdrNew.set(x, v)
• if (acehOld) {
• expose += ',' + x
• }
• resHdrNew.delete(k)
• } else if (
• acehOld &&
• !['cache-control', 'content-language', 'content-type', 'expires', 'last-modified', 'pragma'].includes(k)
• ) {
• expose += ',' + k
• }
• }
•
• if (acehOld) {
• expose += ',--s'
• resHdrNew.set('--t', '1')
• }
•
• if (rawLen) {
• const newLen = resHdrOld.get('content-length') || ''
• const badLen = rawLen !== newLen
•
• if (badLen) {
• if (retryTimes < MAX_RETRY) {
• const newUrlObj = await parseYtVideoRedir(urlObj, newLen, res)
• if (newUrlObj) {
• return proxy(newUrlObj, reqInit, acehOld, rawLen, retryTimes + 1)
• }
• }
•
• return makeRes(res.body, 400, {
• '--error': `bad len: ${newLen}, expect: ${rawLen}`,
• 'access-control-expose-headers': '--error',
• })
• }
•
• if (retryTimes > 1) {
• resHdrNew.set('--retry', retryTimes)
• }
• }
•
• let status = res.status
• resHdrNew.set('access-control-expose-headers', expose)
• resHdrNew.set('access-control-allow-origin', '*')
• resHdrNew.set('--s', status)
• resHdrNew.set('--ver', JS_VER)
•
• resHdrNew.delete('content-security-policy')
• resHdrNew.delete('content-security-policy-report-only')
• resHdrNew.delete('clear-site-data')
•
• if ([301, 302, 303, 307, 308].includes(status)) {
• status += 10
• }
•
• return new Response(res.body, {
• status,
• headers: resHdrNew,
• })
• }
•
• /** 判断是否为 有图比 视频 URL */
• function isYtUrl(urlObj) {
• return (
• urlObj.host.endsWith('.googlevideo.com') &&
• urlObj.pathname.startsWith('/videoplayback')
• )
• }
•
• /** 处理 有图比 视频跳转解析 */
• async function parseYtVideoRedir(urlObj, newLen, res) {
• if (parseInt(newLen) > 2000 || !isYtUrl(urlObj)) {
• return null
• }
• try {
• const data = await res.text()
• const newUrl = newUrl(data)
• return isYtUrl(newUrl) ? newUrl : null
• } catch {
• return null
• }
• }
博客上的教程地址: https://www.cveoy.top/t/topic/qFMo
中国站( aliyun.com )免费领ESA: http://s.tb.cn/e6.0FuRjs (官方链接非aff)
国际站( alibabacloud.com )免费领ESA: http://s.tb.cn/e6.0vy7ie (官方链接非aff)
在 https://esa.console.aliyun.com/edge/function/list 创建一个边缘函数
代码换为以下代码
• 'use strict'
•
• const ASSET_URL = 'https://www.cveoy.top/'
• const JS_VER = 10
• const MAX_RETRY = 1
•
• /** [url=home.php?mod=space&uid=26679]@Type[/url] {RequestInit} */
• const PREFLIGHT_INIT = {
• status: 204,
• headers: new Headers({
• 'access-control-allow-origin': '*',
• 'access-control-allow-methods': 'GET,POST,PUT,PATCH,TRACE,DELETE,HEAD,OPTIONS',
• 'access-control-max-age': '1728000',
• }),
• }
•
• /** 工具函数:生成响应 */
• function makeRes(body, status = 200, headers = {}) {
• headers['--ver'] = JS_VER
• headers['access-control-allow-origin'] = '*'
• return new Response(body, { status, headers })
• }
•
• /** 工具函数:解析 URL */
• function newUrl(urlStr) {
• try {
• return new URL(urlStr)
• } catch (err) {
• return null
• }
• }
•
• /** 入口函数:模块方式导出 */
• export default {
• async fetch(req, env, ctx) {
• return fetchHandler(req).catch(err =>
• makeRes('cfworker error:\n' + err.stack, 502)
• )
• }
• }
•
• /** 主处理函数 */
• async function fetchHandler(req) {
• const urlStr = req.url
• const urlObj = new URL(urlStr)
• const path = urlObj.href.substr(urlObj.origin.length)
•
• // 强制 HTTPS 跳转
• if (urlObj.protocol === 'http:') {
• urlObj.protocol = 'https:'
• return makeRes('', 301, {
• 'strict-transport-security': 'max-age=99999999; includeSubDomains; preload',
• 'location': urlObj.href,
• })
• }
•
• // 代理请求
• if (path.startsWith('/http/')) {
• return httpHandler(req, path.substr(6))
• }
•
• // 特殊路径处理
• switch (path) {
• case '/http':
• return makeRes('请更新到最新版本!')
• case '/ws':
• return makeRes('not support', 400)
• case '/works':
• return makeRes('it works')
• default:
• return fetch(ASSET_URL + path)
• }
• }
•
• /** HTTP 代理处理逻辑 */
• function httpHandler(req, pathname) {
• const reqHdrRaw = req.headers
• if (reqHdrRaw.has('x-jsproxy')) {
• return Response.error()
• }
•
• if (
• req.method === 'OPTIONS' &&
• reqHdrRaw.has('access-control-request-headers')
• ) {
• return new Response(null, PREFLIGHT_INIT)
• }
•
• let acehOld = false
• let rawSvr = ''
• let rawLen = ''
• let rawEtag = ''
•
• const reqHdrNew = new Headers(reqHdrRaw)
• reqHdrNew.set('x-jsproxy', '1')
•
• const refer = reqHdrNew.get('referer') || ''
• const query = refer.includes('?') ? refer.split('?')[1] : ''
• if (!query) {
• return makeRes('missing params', 403)
• }
•
• const param = new URLSearchParams(query)
• for (const [k, v] of param.entries()) {
• if (k.startsWith('--')) {
• switch (k.slice(2)) {
• case 'aceh':
• acehOld = true
• break
• case 'raw-info':
• [rawSvr, rawLen, rawEtag] = v.split('|')
• break
• }
• } else {
• if (v) {
• reqHdrNew.set(k, v)
• } else {
• reqHdrNew.delete(k)
• }
• }
• }
•
• if (!param.has('referer')) {
• reqHdrNew.delete('referer')
• }
•
• const urlStr = pathname.replace(/^(https?):\/+/, '$1://')
• const urlObj = newUrl(urlStr)
• if (!urlObj) {
• return makeRes('invalid proxy url: ' + urlStr, 403)
• }
•
• const reqInit = {
• method: req.method,
• headers: reqHdrNew,
• redirect: 'manual',
• body: req.method === 'POST' ? req.body : undefined,
• }
•
• return proxy(urlObj, reqInit, acehOld, rawLen, 0)
• }
•
• /** 发起代理请求 */
• async function proxy(urlObj, reqInit, acehOld, rawLen, retryTimes) {
• const res = await fetch(urlObj.href, reqInit)
• const resHdrOld = res.headers
• const resHdrNew = new Headers(resHdrOld)
•
• let expose = '*'
•
• for (const [k, v] of resHdrOld.entries()) {
• if (
• k === 'access-control-allow-origin' ||
• k === 'access-control-expose-headers' ||
• k === 'location' ||
• k === 'set-cookie'
• ) {
• const x = '--' + k
• resHdrNew.set(x, v)
• if (acehOld) {
• expose += ',' + x
• }
• resHdrNew.delete(k)
• } else if (
• acehOld &&
• !['cache-control', 'content-language', 'content-type', 'expires', 'last-modified', 'pragma'].includes(k)
• ) {
• expose += ',' + k
• }
• }
•
• if (acehOld) {
• expose += ',--s'
• resHdrNew.set('--t', '1')
• }
•
• if (rawLen) {
• const newLen = resHdrOld.get('content-length') || ''
• const badLen = rawLen !== newLen
•
• if (badLen) {
• if (retryTimes < MAX_RETRY) {
• const newUrlObj = await parseYtVideoRedir(urlObj, newLen, res)
• if (newUrlObj) {
• return proxy(newUrlObj, reqInit, acehOld, rawLen, retryTimes + 1)
• }
• }
•
• return makeRes(res.body, 400, {
• '--error': `bad len: ${newLen}, expect: ${rawLen}`,
• 'access-control-expose-headers': '--error',
• })
• }
•
• if (retryTimes > 1) {
• resHdrNew.set('--retry', retryTimes)
• }
• }
•
• let status = res.status
• resHdrNew.set('access-control-expose-headers', expose)
• resHdrNew.set('access-control-allow-origin', '*')
• resHdrNew.set('--s', status)
• resHdrNew.set('--ver', JS_VER)
•
• resHdrNew.delete('content-security-policy')
• resHdrNew.delete('content-security-policy-report-only')
• resHdrNew.delete('clear-site-data')
•
• if ([301, 302, 303, 307, 308].includes(status)) {
• status += 10
• }
•
• return new Response(res.body, {
• status,
• headers: resHdrNew,
• })
• }
•
• /** 判断是否为 有图比 视频 URL */
• function isYtUrl(urlObj) {
• return (
• urlObj.host.endsWith('.googlevideo.com') &&
• urlObj.pathname.startsWith('/videoplayback')
• )
• }
•
• /** 处理 有图比 视频跳转解析 */
• async function parseYtVideoRedir(urlObj, newLen, res) {
• if (parseInt(newLen) > 2000 || !isYtUrl(urlObj)) {
• return null
• }
• try {
• const data = await res.text()
• const newUrl = newUrl(data)
• return isYtUrl(newUrl) ? newUrl : null
• } catch {
• return null
• }
• }