const whiteListSuffixs = [
  '*', // allow all domain suffix
]
async function handleRequest(request) {
  const urlReq = new URL(request?.url)
  let url = urlReq.href?.replace(urlReq.origin+'/', '').trim()
  if (!url) {
    return new Response(`error code 1, usage: ${urlReq.origin}/http(s)://api.example.com`, {status: 400})
  }
  if (0!==url.indexOf('https://') && 0===url.indexOf('https:')) {
    url = url.replace('https:/', 'https://')
  } else if (0!==url.indexOf('http://') && 0===url.indexOf('http:')) {
    url = url.replace('http:/', 'http://')
  }
  let urlTarget
  try {
    urlTarget = new URL(url)
  } catch(e) {
    return new Response(`error code 2, usage: ${urlReq.origin}/http(s)://api.example.com`, {status: 400})
  }
  if (urlTarget?.port) {
    return new Response('port is not allowed', {status: 400})
  }
  const hostname = urlTarget?.hostname
  if (!hostname) {
    return new Response(`error code 3, usage: ${urlReq.origin}/http(s)://api.example.com`, {status: 400})
  }
  let inWhiteList = false
  for (const suffix of whiteListSuffixs) {
    if (hostname.indexOf(suffix) > -1 || '*'===suffix.trim()) {
      inWhiteList = true
      break
    }
  }
  if (!inWhiteList) {
    return new Response( `${urlTarget.hostname} not in white list`, {status: 403} )
  }
  const response = await fetch(url, {
    headers: request.headers,
    body: request.body,
    method: request.method
  })
  let respHeaders = {}
  response.headers.forEach((value, key)=>respHeaders[key] = value)
  if ('*'!==respHeaders['Access-Control-Allow-Origin']?.trim() && '*'!==respHeaders['access-control-allow-origin']?.trim()) {
    respHeaders['Access-Control-Allow-Origin'] = '*'
  }
  return new Response( await response.body , {
    headers: respHeaders,
    status: response.status
  })
}
addEventListener('fetch', event => {
  return event.respondWith(handleRequest(event.request))
})

已知Bug:如果你反代带端口的url,例如http(s)://example.com:3000/path?query=string,它会自动去除端口再请求,变成请求http(s)://example.com/path?query=string

添加新评论