閣下寫到以上代碼不支援POST方法,而編輯頁面需要使用POST方法,所以只能檢視不能編輯頁面。
,那post方法的代碼是蛤?
在User talk:FL.YL.BANxS/Flow的话题
当时本来想做POST支持,后来还是自觉遵守了m:NOP,所以写了这句话(意思就是我不提供编辑功能,你们想要可以自己写)。
当时还能编辑的,但是现在 Cloudflare 的 IP 段已被全域封禁(Open Proxy),所以已经不需要支持POST方法了。
Cloudflare Workers 使用的是 JavaScript 的 Fetch API,查一下相关文档就知道。
Mozilla 的 Fetch API 文档:
示例(send
是POST发送给服务器的数据,recv
是从服务器接收的数据,moreWork
是接收到数据后做的事,otherWork
是接收到数据前的空闲时间做的事):
/* 同步 */
var reply = await fetch(`https://zh.wikipedia.beta.wmflabs.org${url}`, {
method: 'POST',
body: send
})
var recv = reply.body//这行要等到上一行执行完毕后才执行
moreWork()
//因为是同步所以没有办法做otherWork
/* end */
/* 异步 */
fetch(`https://zh.wikipedia.beta.wmflabs.org${url}`, {
method: 'POST',
body: send
}).then(reply => {
var recv = reply.body
moreWork()
})
otherWork()
/* end */
回复是用event.respondWith(handleRequest(event.request))
完成的,所以handleRequest
这个函数的返回值会被当成是 Response。如果不改这个设计,就必须同步执行(在 handleRequest
函数内做完所有事并返回),不然的话就没东西可以返回,如果不写return就返回undefined,然后undefined就被当成是 Response Object并调用event.respondWith
传过去,然后event.respondWith
接收到无效值,就报错。
所以如果要用异步的话就把async function handleRequest(request) {
这行的上面改成这样,然后在需要的时候调用replyCallback
传入Response:
var replyCallback
addEventListener('fetch', event => {
replyCallback = event.respondWith
handleRequest(event.request)
})
send
是用来比喻“要用POST发送的数据”的,不要照搬(不然就报错ReferenceError),要把它换成一个实际的变量或字符串(比如说body: 'test'
会POST发送内容“test”给服务器),如果你是纯粹转发客户端请求的话写成这样就行:
//request变量是handleRequest函数接收的参数
{
method: request.method,//request的属性method是客户端的HTTP请求方法
body: request.body//如果request.method == 'POST',这个就是客户端POST请求发送过来的数据。
}
另外,因为没有调用replyCallback
函数去返回HTTP回复,所以当然就超时了......
所以,已有的new Response(...)
就不需要return了,直接改成调用replyCallback
传过去就行,所有用到return的地方都需要改(包括try那边的catch)。
因为报错TypeError: Illegal invocation
,所以如果要做异步的话就不能有handleRequest这一层,把操作全放到addEventListener的回调哪里才行,我试了一下还是莫名其妙Connection timed out。
不如干脆用同步算了,比如说这个示例:
/**
* https://********************************.cloudflareworkers.com/
* https://beta.zhwiki.workers.dev/
**/
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request))
})
async function handleRequest(req) {
try{
var url = (new URL(req.url))
if(url.protocol != 'https:'){
url.protocol = 'https:'
return (new Response('', {status: 301, headers: {'Location': url.href}}))
}
var header = (new Headers(req.headers))
var ua = header.get('User-Agent')
var ual = ua.toLowerCase()
var host = url.hostname
var path = url.pathname
var argv = url.search
if(path == '/'){
return (new Response('', {status: 302, headers: {'Location': '/wiki/'}}))
}
if(path == '/w/api.php'){
return (new Response('Api error', {status: 403, statusText: 'Error : https://beta.zhwiki.workers.dev/ can\'t not use MediaWiki Api'}))
}
var res = await fetch(`https://zh.wikipedia.beta.wmflabs.org${path}${argv}`, {
method : req.method,
body: req.body
})
return (new Response(res.body, {status: res.status, headers: res.headers}))
} catch(err){
return (new Response(err, {status: 500}))
}
}
意思說他異步會出錯?
报错TypeError: Illegal invocation
就说明这个函数是上下文敏感的,所以要做异步的话就要保持上下文一致:
addEventListener('fetch', event => {
handleRequest(event.request, (...args) => event.respondWith.apply(event, args))
})
async function handleRequest(req, replyCallback) {
然而还是Connection timed out,debug:
async function handleRequest(req, replyCallback) {
replyCallback(new Response('Test'))
return
能正常输出“Test”(上下文问题解决了),难道是then的回调没有被调用导致超时?但是我在浏览器F12那里测试fetch发现then的回调是会被调用的,那就说明是 Cloudflare Workers 自己没有实现这个。
所以说 JavaScript 是可以异步的,但是 Cloudflare Workers 不行(要用await)。
什么意思?如果是函数的话那还是同步的。
另外,应用场景如果不需要并发的话用异步没有优势,用同步也没有劣势。