Cloudflare Workers - 使用 Vuejs 的 SPA
Cloudflare Workers - SPA with Vuejs
您好,我已经使用以下命令将 Vue.js 应用程序部署到 Cloudflare 工作人员:
wrangler generate --site
wrangler publish --env dev
这是我的 wrangler.toml:
account_id = "xxx"
name = "name"
type = "webpack"
workers_dev = true
[site]
bucket = "./dist"
entry-point = "workers-site"
[env.dev]
name = "name"
route = "xxx.com/*"
zone_id = "XXX"
account_id = "XXX"
该网站在 "xxx.com" 上正常运行,但是当我在任何其他路径上刷新页面时,我收到此错误消息:
could not find es-es/index.html in your content namespace
或者例如:
could not find category/65/index.html in your content namespace
在 nginx 上我必须创建一个 .htaccess,但我不知道如何让它在这里工作。
这是我的 index.js 以防有帮助:
import { getAssetFromKV, mapRequestToAsset } from '@cloudflare/kv-asset-handler'
/**
* The DEBUG flag will do two things that help during development:
* 1. we will skip caching on the edge, which makes it easier to
* debug.
* 2. we will return an error message on exception in your Response rather
* than the default 404.html page.
*/
const DEBUG = false
addEventListener('fetch', event => {
try {
event.respondWith(handleEvent(event))
} catch (e) {
if (DEBUG) {
return event.respondWith(
new Response(e.message || e.toString(), {
status: 500,
}),
)
}
event.respondWith(new Response('Internal Error', { status: 500 }))
}
})
async function handleEvent(event) {
const url = new URL(event.request.url)
let options = {}
/**
* You can add custom logic to how we fetch your assets
* by configuring the function `mapRequestToAsset`
*/
// options.mapRequestToAsset = handlePrefix(/^\/docs/)
try {
if (DEBUG) {
// customize caching
options.cacheControl = {
bypassCache: true,
}
}
return await getAssetFromKV(event, options)
} catch (e) {
// if an error is thrown try to serve the asset at 404.html
if (!DEBUG) {
try {
let notFoundResponse = await getAssetFromKV(event, {
mapRequestToAsset: req => new Request(`${new URL(req.url).origin}/404.html`, req),
})
return new Response(notFoundResponse.body, { ...notFoundResponse, status: 404 })
} catch (e) {}
}
return new Response(e.message || e.toString(), { status: 500 })
}
}
/**
* Here's one example of how to modify a request to
* remove a specific prefix, in this case `/docs` from
* the url. This can be useful if you are deploying to a
* route on a zone, or if you only want your static content
* to exist at a specific path.
*/
function handlePrefix(prefix) {
return request => {
// compute the default (e.g. / -> index.html)
let defaultAssetKey = mapRequestToAsset(request)
let url = new URL(defaultAssetKey.url)
// strip the prefix from the path for lookup
url.pathname = url.pathname.replace(prefix, '/')
// inherit all other props from the default request
return new Request(url.toString(), defaultAssetKey)
}
}
如您所知,Vue.js(与许多其他 SPA 框架一样)期望对于未映射到特定文件的任何路径,服务器回退到为根 /index.html
文件提供服务.然后 Vue 将在浏览器端进行路由 JavaScript。您提到您知道如何使用 .htaccess
完成此回退,但我们如何使用 Worker 完成此操作?
好消息:在Workers中,我们可以写代码做任何我们想做的事情!
事实上,worker 代码已经有一个特定的代码块来处理“404 not found”错误。解决该问题的一种方法是更改此代码块,使其不再返回 404 错误,而是 returns /index.html
.
我们要更改的代码是这部分:
} catch (e) {
// if an error is thrown try to serve the asset at 404.html
if (!DEBUG) {
try {
let notFoundResponse = await getAssetFromKV(event, {
mapRequestToAsset: req => new Request(`${new URL(req.url).origin}/404.html`, req),
})
return new Response(notFoundResponse.body, { ...notFoundResponse, status: 404 })
} catch (e) {}
}
return new Response(e.message || e.toString(), { status: 500 })
}
我们想将其更改为:
} catch (e) {
// Fall back to serving `/index.html` on errors.
return getAssetFromKV(event, {
mapRequestToAsset: req => new Request(`${new URL(req.url).origin}/index.html`, req),
})
}
这应该可以解决问题。
但是,上面的解决方案有一个小问题:对于任何 HTML 页面(根除外),它会进行两次查找,首先查找特定路径,然后才查找/index.html
作为备用。这些查找非常快,但也许我们可以通过更智能一点并根据 URL.
预先检测 HTML 页面来加快速度
为此,我们要自定义 mapRequestToAsset
函数。您可以在代码的注释中看到有关此的提示:
/**
* You can add custom logic to how we fetch your assets
* by configuring the function `mapRequestToAsset`
*/
// options.mapRequestToAsset = handlePrefix(/^\/docs/)
让我们继续使用它。将上面的注释替换为:
options.mapRequestToAsset = req => {
// First let's apply the default handler, which we imported from
// '@cloudflare/kv-asset-handler' at the top of the file. We do
// this because the default handler already has logic to detect
// paths that should map to HTML files, for which it appends
// `/index.html` to the path.
req = mapRequestToAsset(req)
// Now we can detect if the default handler decided to map to
// index.html in some specific directory.
if (req.url.endsWith('/index.html')) {
// Indeed. Let's change it to instead map to the root `/index.html`.
// This avoids the need to do a redundant lookup that we know will
// fail.
return new Request(`${new URL(req.url).origin}/index.html`, req)
} else {
// The default handler decided this is not an HTML page. It's probably
// an image, CSS, or JS file. Leave it as-is.
return req
}
}
现在代码专门检测 HTML 请求并用根 /index.html
替换它们,因此无需浪费时间查找不存在的文件只是为了捕获由此产生的错误.对于其他类型的文件(图片、JS、CSS等)代码不会修改文件名。
现在似乎有一种内置方式可以做到这一点:
import { getAssetFromKV, serveSinglePageApp } from '@cloudflare/kv-asset-handler'
...
let asset = await getAssetFromKV(event, { mapRequestToAsset: serveSinglePageApp })
https://github.com/cloudflare/kv-asset-handler#servesinglepageapp
您好,我已经使用以下命令将 Vue.js 应用程序部署到 Cloudflare 工作人员:
wrangler generate --site
wrangler publish --env dev
这是我的 wrangler.toml:
account_id = "xxx"
name = "name"
type = "webpack"
workers_dev = true
[site]
bucket = "./dist"
entry-point = "workers-site"
[env.dev]
name = "name"
route = "xxx.com/*"
zone_id = "XXX"
account_id = "XXX"
该网站在 "xxx.com" 上正常运行,但是当我在任何其他路径上刷新页面时,我收到此错误消息:
could not find es-es/index.html in your content namespace
或者例如:
could not find category/65/index.html in your content namespace
在 nginx 上我必须创建一个 .htaccess,但我不知道如何让它在这里工作。
这是我的 index.js 以防有帮助:
import { getAssetFromKV, mapRequestToAsset } from '@cloudflare/kv-asset-handler'
/**
* The DEBUG flag will do two things that help during development:
* 1. we will skip caching on the edge, which makes it easier to
* debug.
* 2. we will return an error message on exception in your Response rather
* than the default 404.html page.
*/
const DEBUG = false
addEventListener('fetch', event => {
try {
event.respondWith(handleEvent(event))
} catch (e) {
if (DEBUG) {
return event.respondWith(
new Response(e.message || e.toString(), {
status: 500,
}),
)
}
event.respondWith(new Response('Internal Error', { status: 500 }))
}
})
async function handleEvent(event) {
const url = new URL(event.request.url)
let options = {}
/**
* You can add custom logic to how we fetch your assets
* by configuring the function `mapRequestToAsset`
*/
// options.mapRequestToAsset = handlePrefix(/^\/docs/)
try {
if (DEBUG) {
// customize caching
options.cacheControl = {
bypassCache: true,
}
}
return await getAssetFromKV(event, options)
} catch (e) {
// if an error is thrown try to serve the asset at 404.html
if (!DEBUG) {
try {
let notFoundResponse = await getAssetFromKV(event, {
mapRequestToAsset: req => new Request(`${new URL(req.url).origin}/404.html`, req),
})
return new Response(notFoundResponse.body, { ...notFoundResponse, status: 404 })
} catch (e) {}
}
return new Response(e.message || e.toString(), { status: 500 })
}
}
/**
* Here's one example of how to modify a request to
* remove a specific prefix, in this case `/docs` from
* the url. This can be useful if you are deploying to a
* route on a zone, or if you only want your static content
* to exist at a specific path.
*/
function handlePrefix(prefix) {
return request => {
// compute the default (e.g. / -> index.html)
let defaultAssetKey = mapRequestToAsset(request)
let url = new URL(defaultAssetKey.url)
// strip the prefix from the path for lookup
url.pathname = url.pathname.replace(prefix, '/')
// inherit all other props from the default request
return new Request(url.toString(), defaultAssetKey)
}
}
如您所知,Vue.js(与许多其他 SPA 框架一样)期望对于未映射到特定文件的任何路径,服务器回退到为根 /index.html
文件提供服务.然后 Vue 将在浏览器端进行路由 JavaScript。您提到您知道如何使用 .htaccess
完成此回退,但我们如何使用 Worker 完成此操作?
好消息:在Workers中,我们可以写代码做任何我们想做的事情!
事实上,worker 代码已经有一个特定的代码块来处理“404 not found”错误。解决该问题的一种方法是更改此代码块,使其不再返回 404 错误,而是 returns /index.html
.
我们要更改的代码是这部分:
} catch (e) {
// if an error is thrown try to serve the asset at 404.html
if (!DEBUG) {
try {
let notFoundResponse = await getAssetFromKV(event, {
mapRequestToAsset: req => new Request(`${new URL(req.url).origin}/404.html`, req),
})
return new Response(notFoundResponse.body, { ...notFoundResponse, status: 404 })
} catch (e) {}
}
return new Response(e.message || e.toString(), { status: 500 })
}
我们想将其更改为:
} catch (e) {
// Fall back to serving `/index.html` on errors.
return getAssetFromKV(event, {
mapRequestToAsset: req => new Request(`${new URL(req.url).origin}/index.html`, req),
})
}
这应该可以解决问题。
但是,上面的解决方案有一个小问题:对于任何 HTML 页面(根除外),它会进行两次查找,首先查找特定路径,然后才查找/index.html
作为备用。这些查找非常快,但也许我们可以通过更智能一点并根据 URL.
为此,我们要自定义 mapRequestToAsset
函数。您可以在代码的注释中看到有关此的提示:
/**
* You can add custom logic to how we fetch your assets
* by configuring the function `mapRequestToAsset`
*/
// options.mapRequestToAsset = handlePrefix(/^\/docs/)
让我们继续使用它。将上面的注释替换为:
options.mapRequestToAsset = req => {
// First let's apply the default handler, which we imported from
// '@cloudflare/kv-asset-handler' at the top of the file. We do
// this because the default handler already has logic to detect
// paths that should map to HTML files, for which it appends
// `/index.html` to the path.
req = mapRequestToAsset(req)
// Now we can detect if the default handler decided to map to
// index.html in some specific directory.
if (req.url.endsWith('/index.html')) {
// Indeed. Let's change it to instead map to the root `/index.html`.
// This avoids the need to do a redundant lookup that we know will
// fail.
return new Request(`${new URL(req.url).origin}/index.html`, req)
} else {
// The default handler decided this is not an HTML page. It's probably
// an image, CSS, or JS file. Leave it as-is.
return req
}
}
现在代码专门检测 HTML 请求并用根 /index.html
替换它们,因此无需浪费时间查找不存在的文件只是为了捕获由此产生的错误.对于其他类型的文件(图片、JS、CSS等)代码不会修改文件名。
现在似乎有一种内置方式可以做到这一点:
import { getAssetFromKV, serveSinglePageApp } from '@cloudflare/kv-asset-handler'
...
let asset = await getAssetFromKV(event, { mapRequestToAsset: serveSinglePageApp })
https://github.com/cloudflare/kv-asset-handler#servesinglepageapp