cloudflare Workers 是近期新出的一种serveless的简单的边缘计算服务,就是把简单的JavaScript代码直接安排到cloudflare的cdn服务器上去运行,这样处理的效果会更快。

目前cloudflare对个人免费账户的使用限额每天最多调用十万次,一次的cpu时间不得超过10ms。

官网对cloudflare workers的介绍是:

在覆盖 95 个国家/地区超过 200 个城市的 Cloudflare 全球云网络上构建无服务器应用程序。 Cloudflare Workers 提供了一个轻量级的 JavaScript 执行环境,允许开发人员在不配置或不维护基础设施的情况下,扩充现有应用程序或创建全新应用程序。

按照这个说法在cloudflare Workers 安排的JavaScript是直接运行在cdn里面的,这样就省了cdn回源这一步。当然按照上面的说法,免费账户的这些种种限制并不能使用cloudflare Workers 支撑起一个大型网站的,所以通常来说还是要有内容或者数据源的。

之前看到有大佬在WordPress上面做了一个展示steam库存的页面,按照大佬说法结合github仓库代码,需要从steam社区获取数据,然而 【数据删除】,这显然是不方便的,需要用别人的api或者境外服务器自行搭建。但steam有着自己的一套api,就是Steam Web Api,其中https://api.steampowered.com/到目前为止是可以访问的,而且这个网站仅仅提供json之类的给自动化程序阅读的文本,将来出问题的可能性不大,完全可以绕过steam社区对相关游戏数据进行获取。

这个Api的调用需要API key,登录steam账号之后就可以一键获取,里面的api也很多,涵盖各种信息,具体可以去官方文档里面去看。

按照官方文档的说法,api key分为两种,一种是普通用户的apikey,一个steam账号可以申请一个,申请完了之后还可以注销(没试过),有些api只能用发行商apikey调用,在这类api说明上面都有禁止前端直接调用的警告标志,必须通过安全的服务器调用。普通的api上面则没有这个警告。意思就是可以在前端直接调用?

考虑到前端直接调用等于直接把apikey公开出来,这可能对steam的账号有着不可预知的系统性风险,于是决定还是不在前端直接调用了。如果不在乎账号或者有一个新创的小号或者是steam内部工作人员的背书,那就可以直接在前端调用了,也就会省了好多事。

在“安全的服务器”上调用api的方式有很多,如果是一年前的我,肯定会用flaskjinjia模板直接整一个html页面出来,(那时候就会这个)。如果是一个月前的我,肯定会用flask_restful直接整一个API出来(那时候刚会了api的制作),现在的我决定用cloudflare workers,顺便学一下这种serveless的模式与JavaScript。

在服务端运行的JavaScript之前从来也没有写过,只能照葫芦画瓢,对着官网上的例子和JavaScript教程一点一点搞,最后搞了出来,安排(代理)了其中五个比较常用的api。API最终发布在https://cfwk.dogcraft.top

服务端调用的JavaScript与网页端的差不多,毕竟脚本解释器都是一样的,但还是有区别的,毕竟服务端与浏览器端的工作环境与要求完全不同。

addEventListener('fetch', event => {
  event.respondWith(handleRequest(event.request))
})
/**
 * Respond with hello worker text
 * @param {Request} request
 */
async function handleRequest(request) {
  return new Response('Hello worker!', {
    headers: { 'content-type': 'text/plain' },
  })
}

这个是cloudflare给出的hello world示例 其中

addEventListener('fetch', event => {
  event.respondWith(handleRequest(event.request))
})

应该是监听事件的函数,应该是与JavaScript解释器或cloudflare服务器的运行环境或沙箱对接的一部分,想我这种刚开始写JavaScript一般是不需要改动的,真正处理网络请求的函数是下面那个,返回内容需要new一个Response对象。

从返回数据已经掌握(划掉)了,那获得数据就需要用fetch了,这里的fetch方法应该和前端JavaScript是一样的,前端可以异步调用,但这里就需要同步调用了。不知道是为什么,盲猜回调函数不能返回response到event.respondWith(handleRequest(event.request))所以要用await了。

fetch回来的数据还要await才能读出来,异步方法真是多。

const sde = await fetch(url2+url3,suit) 
// console.log(url2+url3)
return await sde.text();

能通过console.log调试是真的出乎意料……

还有就是url的切分与路由,从一个例子上找到了解决办法。


let su= new URL(request.url);
  var path = su.pathname.split('/')

这会简单的把url且分开,并存储到path这个数组上,然后通过if else
组合就可以处理不同路径的请求了(开始怀念flask的路由处理了)

最后不要忘记允许跨域,不然辛辛苦苦搞了这么多前端没法调用。

 response.headers.set('Access-Control-Allow-Origin', "*")

完整的代码就安排在下面,新开一个workers把下面的粘上就能用,别忘了把const stkey="YOUR STEAM WEB API KEY";改成自己的。

服务端的API到此就算是搞完了,剩下的就是前端页面了……不会css、不会懒加载只会拿bootstrap4往上套的我要哭了

目前前端已经安排完了大部分。目前放在https://www.dogcraft.top/steaminfo/。最近家里的联通网络经常抽风,一抽风github和套上cloudflare的网页就打不开(包括刚搞好的API),具体表现是cloudflare的服务器是可以ping通的,但用tenlent连443端口都没反应,连一个端口关闭的信息都不给,最后都是以链接超时收场。一般一次抽风短则几分钟,长则两三个小时,让人心态崩溃。更让人难受的是我的【数据删除】是过cloudflare的,一旦cloudflare连不上就全完了……剩下的几个功能等网络正常一点再搞,搞完了会尽快把过程发到这里来。

addEventListener('fetch', event => {
  event.respondWith(handleRequest(event.request))
})

/**
 * Respond to the request
 * @param {Request} request
 */
async function handleRequest(request) {
   const init = {
    headers: {
      'content-type': type,
    },
  };
  let su= new URL(request.url);
  var path = su.pathname.split('/')
  //const lud= await fetch('https://sig.dogcraft.top/',init)

if (path[1]=='dog') {
   req = await   dog(request,path);
    
} else if (path[1]=='cat'){

 req = await   cat(request,path);
    
}else  if (path[1]=='sum'){

 req = await   sumf(request,path);
    
}else  if (path[1]=='pig'){

 req = await   fnd(request,path);
    
}else if (path[1]=='zig'){

 req = 'doge';
    
}else



{
   req = "cat";
}
response =  new Response(req, {status: 200});

// console.log(request.referrer);


 response.headers.set('Access-Control-Allow-Origin', "*")

return response;

  
}



const type = 'application/json;charset=UTF-8';
const url2='https://api.steampowered.com/IPlayerService/GetOwnedGames/v0001/';
const url4='https://api.steampowered.com/IPlayerService/GetRecentlyPlayedGames/v0001/';
const url5='https://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/';
const url6='https://api.steampowered.com/ISteamUser/GetFriendList/v0001/'
const stkey="YOUR STEAM WEB API KEY";
const stid = "76561198343712334";

async function dog(resdog1,resdog2) {
  // let r=resdog1;
  let path = resdog2;
// let formData = new FormData();

let stid2 = (resdog2[2])
let url3=`?key=${stkey}&steamid=${stid2}&format=json&include_appinfo=true`;
  let suit= {
    headers: {
      'content-type': type,
    },
  };
const sde = await fetch(url2+url3,suit) 
// console.log(url2+url3)
return await sde.text();
  // return r.url+path[1]+" <->"+path[2]
    
}

async function cat(resdog1,resdog2) {
   let path = resdog2;
// let formData = new FormData();

let stid2 = (resdog2[2])
let url3=`?key=${stkey}&steamid=${stid2}&format=json&include_appinfo=true`;
// formData.append("key","EDQW93AFF9BQ45956DC0FDC30D96DRW6");
  let suit= {
    headers: {
      'content-type': type,
    },
  };


const sde = await fetch(url4+url3,suit) 
// console.log(url2+url3)
return await sde.text();
    
}


async function sumf(resdog1,resdog2) {
let stid2 = (resdog2[2])
let url3=`?key=${stkey}&steamids=${stid2}&format=json`;
  let suit= {
     method: 'GET',
    headers: {
      'content-type': type,
      'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/83.0.4103.61 Chrome/83.0.4103.61 Safari/537.36'
    },
  };
  // console.log(url5+url3);
const sde = await fetch(url5+url3,suit) 
// console.log(sde);
return  await sde.text();
}



async function fnd(resdog1,resdog2) {
let stid2 = (resdog2[2])
let url3=`?key=${stkey}&steamid=${stid2}&format=json`;
  let suit= {
     method: 'GET',
    headers: {
      'content-type': type
      // 'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/83.0.4103.61 Chrome/83.0.4103.61 Safari/537.36'
    },
  };
  // console.log(url5+url3);
const sde = await fetch(url6+url3,suit) 
// console.log(sde);
return  await sde.text();
}