使用前端应用程序部署 akka-http 应用程序
Deployment of akka-http app with frontend app
我想弄清楚如何使用适当的前端应用程序部署 akka-http。
让我们假设我们有提供一些 API 的 akka-http 应用程序。它位于回购协议 A 中。
对于这个服务器端应用程序,我们有前端应用程序(Angular 或 REACT 或其他)。它位于回购 B.
那么应该如何正确部署在一起呢?
我正在概述以下场景:
- 检查 A 存储库
- 导航至 /src/main/public 并签出 B 存储库
- 借助 jar 中的 SBT 构建 akka-http 存储库
- 在专用服务器上部署 jar
场景不好吗?
这可能不是您想要的,但我有一个种子项目,其中包含 Akka Http 和 Angular 5 个合一的存储库(您要求 2 个存储库)配置为部署到 Heroku单测功机。
https://github.com/jdschmitt/akka-angular-heroku
希望对您有所帮助。
最好的方法可能是单独部署前端应用程序。但将后端和前端应用程序部署为单个捆绑包也是一种常见的做法(例如 JHipster 做法)。不过,我可以回答如何捆绑。
为方便起见,您可以在单个 SBT 项目中创建两个模块 - service
和 ui
(前端应用程序的根目录)。一个用于后端,另一个用于前端。
SBT 设置
根据您使用的前端框架,我们将稍微修改 SBT 设置。假设我们使用 React。默认情况下,如果我们 运行 npm build
或 yarn build
,前端捆绑文件将默认位于 ui/build
目录中。我们将在 ui
模块中将 build
目录标记为“资源”:
lazy val `ui` =
project
.in(file("./ui"))
.settings(
resourceGenerators in Compile += buildUi.init
)
lazy val buildUi = taskKey[Seq[File]]("Generate UI resources") := {
val webapp = baseDirectory.value / "build"
val managed = resourceManaged.value
for {
(from, to) <- webapp ** "*" pair Path.rebase(webapp, managed / "main" / "ui")
} yield {
Sync.copy(from, to)
to
}
}
service
模块将依赖于 ui
模块:
lazy val `service` =
project
.in(file("./service"))
.dependsOn(`ui`)
现在,service
可以在您构建 React 应用程序后从 ui
中获取资源文件。
如何与后端一起提供前端应用程序 API
假设您创建了 API 路由,前端将使用这些路由。创建一个以“api”、“v1”、“api/v1”或其他任何开头的 pathPrefix
路由,稍后你会看到为什么我们需要这个前缀:
pathPrefix("api") { // api routes }
并创建另一个为前端资产提供服务的路由:
def assets: Route =
getFromResourceDirectory("ui") ~
pathPrefix("") {
get {
getFromResource("ui/index.html", ContentType(`text/html`, `UTF-8`))
}
}
然后这样加入两条路线:
pathPrefix("api") seal { // api routes } ~ assets
瞧!
让我们解释一下这些路线。
首先,我们要匹配我们的 API 路线,因为它们位于特定的 URL。 assets
匹配所有其他 URL。这意味着,访问任何不以 /api
开头的 URL 将 return React 的静态资源。
接下来,让我们剖析assets
条路线:
第一个是 getFromResourceDirectory("ui")
。还记得我们将 ui/build
目录标记为资源目录吗?这意味着我们的 React 资源位于 target/scala/classes/ui
目录中,我们可以简单地以这种方式提供它们。
第二个也是最棘手的一个:
pathPrefix("") {
get {
getFromResource("ui/index.html", ContentType(`text/html`, `UTF-8`))
}
}
这意味着任何不以 /api
开头的 URL 将匹配此路由和 return React 的 index.html
文件。但您可能会问:“为什么我们不直接使用 pathSingleSlash
?”这正是棘手的部分 - 前端框架路由。
假设我们使用 pathSingleSlash
(我们仅在根“/”上公开 React 的资源)。假设我们使用例如react-router-dom
用于 React 应用程序中的路由。我们有一个很好的“/users”路由,可以在 table 中显示用户。我们转到“/”-> Akka HTTP 服务器提供静态文件,一切都按预期工作->我们单击一些转到“/users”的按钮,一切都按预期再次工作,因为 React 路由器现在正在执行路由-> 然后我们刷新我们的页面,我们得到一个 404 错误。为什么?因为它在 React 应用程序中是已知路由,但在 Akka HTTP 服务器中是未知路由。因此,在除 API 路由 ("/api") 之外的任何路由中,我们都希望公开我们的 React 资源。使用 pathPrefix("")
,我们正是这样做的。当我们转到“/users”页面并点击刷新时,Akka HTTP 仍然 returns React 的资源,其余的路由魔术由 React 完成 - “/users”页面成功呈现。
您还可以创建 CORS 路由,这样您就可以在开发阶段从后端独立 运行 前端。
哈金快乐。
我想弄清楚如何使用适当的前端应用程序部署 akka-http。
让我们假设我们有提供一些 API 的 akka-http 应用程序。它位于回购协议 A 中。 对于这个服务器端应用程序,我们有前端应用程序(Angular 或 REACT 或其他)。它位于回购 B.
那么应该如何正确部署在一起呢?
我正在概述以下场景:
- 检查 A 存储库
- 导航至 /src/main/public 并签出 B 存储库
- 借助 jar 中的 SBT 构建 akka-http 存储库
- 在专用服务器上部署 jar
场景不好吗?
这可能不是您想要的,但我有一个种子项目,其中包含 Akka Http 和 Angular 5 个合一的存储库(您要求 2 个存储库)配置为部署到 Heroku单测功机。
https://github.com/jdschmitt/akka-angular-heroku
希望对您有所帮助。
最好的方法可能是单独部署前端应用程序。但将后端和前端应用程序部署为单个捆绑包也是一种常见的做法(例如 JHipster 做法)。不过,我可以回答如何捆绑。
为方便起见,您可以在单个 SBT 项目中创建两个模块 - service
和 ui
(前端应用程序的根目录)。一个用于后端,另一个用于前端。
SBT 设置
根据您使用的前端框架,我们将稍微修改 SBT 设置。假设我们使用 React。默认情况下,如果我们 运行 npm build
或 yarn build
,前端捆绑文件将默认位于 ui/build
目录中。我们将在 ui
模块中将 build
目录标记为“资源”:
lazy val `ui` =
project
.in(file("./ui"))
.settings(
resourceGenerators in Compile += buildUi.init
)
lazy val buildUi = taskKey[Seq[File]]("Generate UI resources") := {
val webapp = baseDirectory.value / "build"
val managed = resourceManaged.value
for {
(from, to) <- webapp ** "*" pair Path.rebase(webapp, managed / "main" / "ui")
} yield {
Sync.copy(from, to)
to
}
}
service
模块将依赖于 ui
模块:
lazy val `service` =
project
.in(file("./service"))
.dependsOn(`ui`)
现在,service
可以在您构建 React 应用程序后从 ui
中获取资源文件。
如何与后端一起提供前端应用程序 API
假设您创建了 API 路由,前端将使用这些路由。创建一个以“api”、“v1”、“api/v1”或其他任何开头的 pathPrefix
路由,稍后你会看到为什么我们需要这个前缀:
pathPrefix("api") { // api routes }
并创建另一个为前端资产提供服务的路由:
def assets: Route =
getFromResourceDirectory("ui") ~
pathPrefix("") {
get {
getFromResource("ui/index.html", ContentType(`text/html`, `UTF-8`))
}
}
然后这样加入两条路线:
pathPrefix("api") seal { // api routes } ~ assets
瞧!
让我们解释一下这些路线。
首先,我们要匹配我们的 API 路线,因为它们位于特定的 URL。 assets
匹配所有其他 URL。这意味着,访问任何不以 /api
开头的 URL 将 return React 的静态资源。
接下来,让我们剖析assets
条路线:
第一个是 getFromResourceDirectory("ui")
。还记得我们将 ui/build
目录标记为资源目录吗?这意味着我们的 React 资源位于 target/scala/classes/ui
目录中,我们可以简单地以这种方式提供它们。
第二个也是最棘手的一个:
pathPrefix("") {
get {
getFromResource("ui/index.html", ContentType(`text/html`, `UTF-8`))
}
}
这意味着任何不以 /api
开头的 URL 将匹配此路由和 return React 的 index.html
文件。但您可能会问:“为什么我们不直接使用 pathSingleSlash
?”这正是棘手的部分 - 前端框架路由。
假设我们使用 pathSingleSlash
(我们仅在根“/”上公开 React 的资源)。假设我们使用例如react-router-dom
用于 React 应用程序中的路由。我们有一个很好的“/users”路由,可以在 table 中显示用户。我们转到“/”-> Akka HTTP 服务器提供静态文件,一切都按预期工作->我们单击一些转到“/users”的按钮,一切都按预期再次工作,因为 React 路由器现在正在执行路由-> 然后我们刷新我们的页面,我们得到一个 404 错误。为什么?因为它在 React 应用程序中是已知路由,但在 Akka HTTP 服务器中是未知路由。因此,在除 API 路由 ("/api") 之外的任何路由中,我们都希望公开我们的 React 资源。使用 pathPrefix("")
,我们正是这样做的。当我们转到“/users”页面并点击刷新时,Akka HTTP 仍然 returns React 的资源,其余的路由魔术由 React 完成 - “/users”页面成功呈现。
您还可以创建 CORS 路由,这样您就可以在开发阶段从后端独立 运行 前端。
哈金快乐。