龙空技术网

Go WebAssembly 教程

杨同学编程 276

前言:

当前各位老铁们对“web页面怎么获取flag”都比较着重,大家都想要剖析一些“web页面怎么获取flag”的相关内容。那么小编也在网上网罗了一些对于“web页面怎么获取flag””的相关资讯,希望朋友们能喜欢,我们快快来学习一下吧!

更新- 本教程中的代码已更新以适应 Go v1.12 中的重大更改

欢迎大家!随着 Go v1.11 刚刚发布,其中就包含一个 WebAssembly 的实验性端口,我认为可以看看我们如何编写自己的 Go 程序并直接编译到 WebAssembly 会很棒!

因此,在本文中,我们将构建一个非常简单的计算器,让我们了解如何编写可以暴露给前端的函数、评估 DOM 元素并随后使用任何结果更新任何 DOM 元素。我们调用的函数。

这有望向您展示为前端应用程序编写和编译您自己的基于 Go 程序需要什么。

注意 -如果您还没有从开头猜到,本教程需要使用 Go v1.11!

介绍

那么这对 Go 和 Web 开发人员来说到底意味着什么呢?好吧,它使我们能够使用 Go 语言编写前端 Web 应用程序,并随后使用其所有很酷的功能,例如类型安全、 goroutines等。

现在,这不是我们第一次看到 Go 语言用于前端的目的。GopherJS 已经存在了很长一段时间并且非常成熟,但是,不同之处在于它将 Go 代码编译为 JS 而不是 WebAssembly。

一个简单的例子

让我们从一个非常简单的示例开始,Hello World每当我们单击网页中的按钮时,它都会在控制台中简单地输出 。我知道这听起来令人兴奋,但我们可以很快将其构建为更实用、更酷的东西:

package mainfunc main() {    println("Hello World")}

现在,为了编译它,您必须设置GOARCH=wasm并且GOOS=js 您还必须使用-o标志指定文件的名称,如下所示:

$ GOARCH=wasm GOOS=js go build -o lib.wasm main.go

这个命令应该将我们的代码编译成lib.wasm是我们当前工作目录中的一个文件。我们将使用该WebAssembly.instantiateStreaming() 函数将其加载到我们的index.html. 注意 - 此代码是从官方 Go 语言存储库中窃取的:

<!DOCTYPE html><!--Copyright 2018 The Go Authors. All rights reserved.Use of this source code is governed by a BSD-stylelicense that can be found in the LICENSE file.--><html>  <head>    <meta charset="utf-8" />    <title>Go wasm</title>  </head>  <body>    <script src="wasm_exec.js"></script>    <script>      if (!WebAssembly.instantiateStreaming) {        // polyfill        WebAssembly.instantiateStreaming = async (resp, importObject) => {          const source = await (await resp).arrayBuffer();          return await WebAssembly.instantiate(source, importObject);        };      }      const go = new Go();      let mod, inst;      WebAssembly.instantiateStreaming(fetch("lib.wasm"), go.importObject).then(        result => {          mod = result.module;          inst = result.instance;          document.getElementById("runButton").disabled = false;        }      );      async function run() {        await go.run(inst);        inst = await WebAssembly.instantiate(mod, go.importObject); // reset instance      }    </script>    <button onClick="run();" id="runButton" disabled>Run</button>  </body></html>

我们还需要wasm_exec.js从misc/wasm.

$ cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" .

而且,我们还有一个简单的net/http基于文件服务器,再次从这里窃取 ,用于提供我们 index.html和我们的其他各种 WebAssembly 文件:

package mainimport (    "flag"    "log"    "net/http")var (    listen = flag.String("listen", ":8080", "listen address")    dir    = flag.String("dir", ".", "directory to serve"))func main() {    flag.Parse()    log.Printf("listening on %q...", *listen)    log.Fatal(http.ListenAndServe(*listen, http.FileServer(http.Dir(*dir))))}

当您localhost:8080启动该服务器后导航到该服务器时,您应该会看到该Run按钮是可点击的,如果您在浏览器中打开您的控制台,您应该会看到Hello World每次点击该按钮时它都会打印出来!

太棒了,我们已经成功编译了一个非常简单的 Go -> WebAssembly 项目并让它在浏览器中运行。

一个更复杂的例子

现在是好的。比如说,我们想要创建一个更复杂的示例,其中包含 DOM 操作、可以绑定到按钮点击的自定义 Go 函数等等。谢天谢地,这并不是太难!

注册函数

我们将首先创建一些我们想要向前端公开的我们自己的函数。我今天感觉很没有原创性,所以这些将是公正的 add和subtract。

这些函数接受一个类型的数组,js.Value并使用该 js.Global().Set()函数设置output为等于我们函数中完成的任何计算的结果。为了更好地衡量,我们还将结果也打印到控制台上:

func add(i []js.Value) {    js.Global().Set("output", js.ValueOf(i[0].Int()+i[1].Int()))    println(js.ValueOf(i[0].Int() + i[1].Int()).String())}func subtract(i []js.Value) {    js.Global().Set("output", js.ValueOf(i[0].Int()-i[1].Int()))    println(js.ValueOf(i[0].Int() - i[1].Int()).String())}func registerCallbacks() {    js.Global().Set("add", js.NewCallback(add))    js.Global().Set("subtract", js.NewCallback(subtract))}func main() {    c := make(chan struct{}, 0)    println("WASM Go Initialized")    // register functions    registerCallbacks()    <-c}

您会注意到我们main通过调用make 和创建一个新频道对我们的函数进行了轻微修改。这有效地将我们之前短暂的程序变成了一个长期运行的程序。我们还调用了另一个registerCallbacks()几乎像路由器的函数 ,而是创建了新的回调函数,将我们新创建的函数有效地绑定到我们的前端。

为了index.html让它工作,我们必须稍微修改一下我们的 JavaScript 代码,以便在获取它后立即运行我们的程序实例:

const go = new Go();let mod, inst;WebAssembly.instantiateStreaming(fetch("lib.wasm"), go.importObject).then(  async result => {    mod = result.module;    inst = result.instance;    await go.run(inst);  });

再次在您的浏览器中加载它,您应该会看到,在没有按下任何按钮的情况下,WASM Go Initialized在控制台中打印出来。这意味着一切都奏效了。

然后我们可以开始从<button> 像这样的元素调用这些函数:

<button onClick="add(2,3);" id="addButton">Add</button><button onClick="subtract(10,3);" id="subtractButton">Subtract</button>

删除现有Run按钮并将这两个新按钮添加到您的 index.html. 当您在浏览器中重新加载页面并打开控制台时,您应该能够看到此函数的输出打印出来。

我们正在缓慢但肯定地开始在这方面取得进展!

评估 DOM 元素

所以,我猜下一阶段是开始评估 DOM 元素并使用它们的值而不是硬编码值。

让我们修改add()函数,以便我可以传入 2 ids<input/> 元素,然后添加这些元素的值,如下所示:

func add(i []js.Value) {    value1 := js.Global().Get("document").Call("getElementById", i[0].String()).Get("value").String()    value2 := js.Global().Get("document").Call("getElementById", i[1].String()).Get("value").String()    js.Global().Set("output", value1+value2)    println(value1 + value2)}

然后我们可以更新我们index.html的代码以具有以下代码:

<input type="text" id="value1" /><input type="text" id="value2" /><button onClick="add('value1', 'value2');" id="addButton">Add</button>

如果您在我们的两个输入中输入一些数值,然后单击Add 按钮,您应该希望在控制台中看到打印出的两个值得串联。

我们忘记了什么?我们需要将这些字符串值解析出来 int 值:

func add(i []js.Value) {    value1 := js.Global().Get("document").Call("getElementById", i[0].String()).Get("value").String()    value2 := js.Global().Get("document").Call("getElementById", i[1].String()).Get("value").String()    int1, _ := strconv.Atoi(value1)    int2, _ := strconv.Atoi(value2)    js.Global().Set("output", int1+int2)    println(int1 + int2)}

您可能会注意到我没有在这里处理错误,因为我感觉很懒惰,这只是为了展示。

现在,尝试重新编译代码并重新加载浏览器,你应该注意到,如果我们输入值22,并3在双方的投入,它成功地输出 25在控制台中。

操作 DOM 元素

如果我们的计算器实际上没有在我们的页面中报告结果,它就不会很好,所以现在让id我们通过将结果输出到三分之一来解决这个问题:

func add(i []js.Value) {    value1 := js.Global().Get("document").Call("getElementById", i[0].String()).Get("value").String()    value2 := js.Global().Get("document").Call("getElementById", i[1].String()).Get("value").String()    int1, _ := strconv.Atoi(value1)    int2, _ := strconv.Atoi(value2)    js.Global().Get("document").Call("getElementById", i[2].String()).Set("value", int1+int2)}
更新我们的减法函数:

最后,让我们更新我们的减法方法:

func subtract(i []js.Value) {    value1 := js.Global().Get("document").Call("getElementById", i[0].String()).Get("value").String()    value2 := js.Global().Get("document").Call("getElementById", i[1].String()).Get("value").String()    int1, _ := strconv.Atoi(value1)    int2, _ := strconv.Atoi(value2)    js.Global().Get("document").Call("getElementById", i[2].String()).Set("value", int1-int2)}

我们的成品index.html应该是这样的:

<!DOCTYPE html><!--Copyright 2018 The Go Authors. All rights reserved.Use of this source code is governed by a BSD-stylelicense that can be found in the LICENSE file.--><html>  <head>    <meta charset="utf-8" />    <title>Go wasm</title>  </head>  <body>    <script src="wasm_exec.js"></script>    <script>      if (!WebAssembly.instantiateStreaming) {        // polyfill        WebAssembly.instantiateStreaming = async (resp, importObject) => {          const source = await (await resp).arrayBuffer();          return await WebAssembly.instantiate(source, importObject);        };      }      const go = new Go();      let mod, inst;      WebAssembly.instantiateStreaming(fetch("lib.wasm"), go.importObject).then(        async result => {          mod = result.module;          inst = result.instance;          await go.run(inst);        }      );    </script>    <input type="text" id="value1" />    <input type="text" id="value2" />    <button onClick="add('value1', 'value2', 'result');" id="addButton">      Add    </button>    <button      onClick="subtract('value1', 'value2', 'result');"      id="subtractButton"    >      Subtract    </button>    <input type="text" id="result" />  </body></html>
结论

因此,在本教程中,我们设法学习了如何使用 Go 语言的新 v1.11 将 Go 程序编译成 WebAssembly。我们创建了一个非常简单的计算器,它将 Go 代码中的函数暴露给我们的前端,并进行一些 DOM 解析和操作以启动。

希望您发现这篇文章有用/有趣!如果你这样做了,那么我很乐意在下面的评论部分收到你的来信。

标签: #web页面怎么获取flag