使用vue3创建vue项目
When I first started with Go programming I found it pretty hard to get my head around it. It was way more low-level than anything else I had ever coded in.
当我刚开始使用Go编程时,我发现很难理解。 它比我以前编写的任何其他代码都更底层。
Fast forward a few months and now I'm a total fan and use it for a lot of projects.
快进几个月,现在我是一个狂热的粉丝,并将其用于许多项目。
In this article, I'll show you how I set up a full-stack web application with Go and Vue.
在本文中,我将向您展示如何使用Go和Vue设置完整的Web应用程序。
Let's dive in!
让我们潜入吧!
我们将要创造的 (What we're going to create)
I thought it would be cool to create a website thumbnail generator. The idea is that you enter a website URL and the application will generate a thumbnail of that website for you.
我认为创建网站缩略图生成器会很酷。 想法是您输入一个网站URL,应用程序将为您生成该网站的缩略图。
设置Go模块 (Setting up a Go module)
First, I create a new directory. Then I set up a Go module by running the following command.
首先,我创建一个新目录。 然后,我通过运行以下命令来设置Go模块。
go mod init github.com/Dirk94/website-thumbnail-generator
This will create a go.mod
file that keeps track of all the module dependencies. This is similar to the package.json
file in a node project.
这将创建一个go.mod
文件,该文件跟踪所有模块依赖性。 这类似于节点项目中的package.json
文件。
Next, I create a new directory main
in which I add a server.go
file. This will be the main entry point of the application.
接下来,我创建一个新的目录main
在其中添加server.go
文件。 这将是应用程序的主要入口点。
For now, let's just print a "hello world" message.
现在,让我们只打印“ hello world”消息。
package main
import "fmt"
func main() {
fmt.Println("Hello world")
}
To run the program I run the following command from the project directory.
要运行该程序,请从项目目录运行以下命令。
go run main/server.go
Hello world
Great, so far everything works! 🙌
太好了,到目前为止一切正常! 🙌
设置网络服务器 (Setting up a web server)
We should create a web server that will listen for incoming requests.
我们应该创建一个Web服务器来侦听传入的请求。
Let's update the main function.
让我们更新主要功能。
func main() {
http.HandleFunc("/", homePageHandler)
fmt.Println("Server listening on port 3000")
log.Panic(
http.ListenAndServe(":3000", nil),
)
}
This will start up a web server and listen on port 3000.
这将启动Web服务器并监听端口3000。
Any request coming in will be handled by the homePageHandler
function. This does not yet exist so let's create it.
任何homePageHandler
请求都将由homePageHandler
函数处理。 目前尚不存在,因此让我们创建它。
func homePageHandler(w http.ResponseWriter, r *http.Request) {
_, err := fmt.Fprintf(w, "hello world")
checkError(err)
}
func checkError(err error) {
if err != nil {
log.Panic(err)
}
}
All this function does is write "hello world" to the http.ResponseWriter
此功能所做的全部工作就是将“ hello world”写入http.ResponseWriter
The checkError
function is simply a handy function that will stop the program and print a stack trace if the error
is not nil.
checkError
函数只是一个方便的函数,如果error
不是nil,它将停止程序并打印堆栈跟踪。
When running the program the web server prints the "hello world" message correctly!
运行该程序时,Web服务器将正确打印“ hello world”消息!
创建Vue项目 (Creating the Vue project)
To create a new Vue project I run the following command from the project directory.
要创建一个新的Vue项目,请从项目目录运行以下命令。
vue create frontend
This creates a lot of files but don't be overwhelmed. Let's begin by running the Vue development server.
这会创建很多文件,但不会被淹没。 让我们从运行Vue开发服务器开始。
yarn serve
When navigating to localhost:8081 you can see that the Vue app works!
导航到localhost:8081时,您可以看到Vue应用程序正常运行!
Alright, let's clean up the frontend directory a bit.
好吧,让我们稍微整理一下前端目录。
For starters, I delete the assets
and components
directory as I won't use them.
首先,我将删除assets
和components
目录,因为我不会使用它们。
Then I update the App.vue
file.
然后,我更新App.vue
文件。
<template>
<div id="app" class="container">
<div class="row">
<div class="col-md-6 offset-md-3 py-5">
<h1>Generate a thumbnail of a website</h1>
<form v-on:submit.prevent="makeWebsiteThumbnail">
<div class="form-group">
<input v-model="websiteUrl" type="text" id="website-input" placeholder="Enter a website" class="form-control">
</div>
<div class="form-group">
<button class="btn btn-primary">Generate!</button>
</div>
</form>
</div>
</div>
</div>
</template>
I use the v-model
tag and I call a makeWebsiteThumbnail
function when the form submits. Right now these don't exist. Let's add them.
我使用v-model
标记,并在表单提交时调用makeWebsiteThumbnail
函数。 现在这些都不存在。 让我们添加它们。
<script>
export default {
name: 'App',
data() { return {
websiteUrl: '',
} },
methods: {
makeWebsiteThumbnail() {
console.log(`I should create a website thumbnail of ${this.websiteUrl}`);
}
}
}
</script>
I'm also using some Bootstrap 4 classes, so for that to work I must add the bootstrap CSS to the public/index.html
file.
我还使用了一些Bootstrap 4类,因此要使其正常工作,我必须将bootstrap CSS添加到public/index.html
文件中。
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<!--- The other stuff in the head tag here... -->
</head>
Alright, let's fire up the web server and check if we see the log message.
好了,让我们启动Web服务器并检查是否看到日志消息。
Nice, it works! 🔥
很好,可以用! 🔥
创建网站缩略图 (Creating a website thumbnail)
To create the website thumbnail I'm going to use screenshotapi.net. That way I only have to call an API to do the heavy lifting for me.
要创建网站缩略图,我将使用screenshotapi.net 。 这样,我只需要调用API即可为我完成繁重的工作。
First I install axios.
首先,我安装axios。
yarn add axios
Then I import it in the App.vue
file.
然后,将其导入App.vue
文件中。
<script>
import axios from 'axios';
export default {
name: 'App',
// The rest here...
Next, I update the makeWebsiteThumbnail
function to actually call the screenshot API.
接下来,我更新makeWebsiteThumbnail
函数以实际调用屏幕快照API。
makeWebsiteThumbnail() {
axios.post("https://screenshotapi.net/api/v1/screenshot", {
token: "SCREENSHOTAPI_TOKEN",
url: this.websiteUrl,
width: 1920,
height: 1080,
output: 'json',
thumbnail_width: 300
})
.then((response) => {
this.thumbnailUrl = response.data.screenshot;
})
.catch((error) => {
window.alert(`The API returned an error: ${error}`);
})
}
Make sure to replace the SCREENSHOTAPI_TOKEN
with your token.
确保用您的令牌替换SCREENSHOTAPI_TOKEN
。
I set the variable thumbnailUrl
to the screenshot URL that is created by the API. To make this work I have to add 2 things.
我将变量thumbnailUrl
设置为由API创建的屏幕快照URL。 为了使这项工作,我必须添加两件事。
First, I add the thumbnailUrl
variable to the Vue data
object.
首先,我将thumbnailUrl
变量添加到Vue data
对象。
data: {
websiteUrl: '',
thumbnailUrl: '',
},
Second, I create an img
tag that will display thumbnailUrl
image.
其次,我创建一个img
标签,将显示thumbnailUrl
图像。
<img :src="thumbnailUrl"/>
Let's spin up the web server and see the result:
让我们启动Web服务器并查看结果:
It shows a thumbnail of freeCodeCamp, nice!
它显示了freeCodeCamp的缩略图,太好了!
将Go和Vue粘合在一起 (Gluing Go and Vue together)
Right now we've used the Vue development server to spin up the front end. It works, but the development server should only be used for local development.
现在,我们已经使用Vue开发服务器加速了前端。 它可以工作,但是开发服务器应仅用于本地开发。
When we host this application in a production environment you will want to use a "real" web server to handle the incoming requests.
当我们在生产环境中托管此应用程序时,您将需要使用“真实的” Web服务器来处理传入的请求。
Luckily we have just such a thing: our Go server.
幸运的是,我们有这样的事情:我们的Go服务器。
The first thing we have to do is compile our frontend.
我们要做的第一件事是编译前端。
yarn run build
This creates a dist
directory with the compiled assets.
这将使用已编译资产创建一个dist
目录。
We should update the Go server to serve the files from this directory.
我们应该更新Go服务器以提供该目录中的文件。
To do this I update the main
function in the main.go
file.
为此,我更新了main.go
文件中的main
函数。
func main() {
// Serve static files from the frontend/dist directory.
fs := http.FileServer(http.Dir("./frontend/dist"))
http.Handle("/", fs)
// Start the server.
fmt.Println("Server listening on port 3000")
log.Panic(
http.ListenAndServe(":3000", nil),
)
}
As you can see we simply pass the frontend/dist
directory to the fileserver.
如您所见,我们只是将frontend/dist
目录传递到文件服务器。
When running the go program and navigating to localhost:3000
you can indeed see the application!
当运行go程序并导航到localhost:3000
您确实可以看到该应用程序!
使应用程序更安全 (Making the app more secure)
Right now we have a major security flaw. The screenshot API token is visible in our frontend code.
目前,我们存在一个重大的安全漏洞。 屏幕快照API令牌在我们的前端代码中可见。
This means that anybody that inspects the webpage can steal the token.
这意味着检查网页的任何人都可以窃取令牌。
Let's fix that by using our server to call the screenshot API. That way only the server needs to know the token.
让我们通过使用服务器调用屏幕快照API来解决此问题。 这样,只有服务器需要知道令牌。
In the server.go
I create a new function that will listen for any request to the /api/thumbnail
endpoint.
在server.go
我创建了一个新函数,该函数将侦听对/api/thumbnail
端点的任何请求。
type thumbnailRequest struct {
Url string `json:"url"`
}
func thumbnailHandler(w http.ResponseWriter, r *http.Request) {
var decoded thumbnailRequest
// Try to decode the request into the thumbnailRequest struct.
err := json.NewDecoder(r.Body).Decode(&decoded)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
fmt.Printf("Got the following url: %s\n", decoded.Url)
}
For now we just extract and print the URL parameter from the request.
现在,我们仅从请求中提取并打印URL参数。
To make this work I update the main
function to use our thumbnailHandler
function.
为了完成这项工作,我更新了main
函数以使用我们的thumbnailHandler
函数。
func main() {
// Use the thumbnailHandler function
http.HandleFunc("/api/thumbnail", thumbnailHandler)
fs := http.FileServer(http.Dir("./frontend/dist"))
http.Handle("/", fs)
fmt.Println("Server listening on port 3000")
log.Panic(
http.ListenAndServe(":3000", nil),
)
}
And finally, I should update the App.vue
file to call the Go server instead of the screenshot API.
最后,我应该更新App.vue
文件以调用Go服务器,而不是截图API。
makeWebsiteThumbnail() {
// Call the Go API, in this case we only need the URL parameter.
axios.post("http://localhost:3000/api/thumbnail", {
url: this.websiteUrl,
})
.then((response) => {
this.thumbnailUrl = response.data.screenshot;
})
.catch((error) => {
window.alert(`The API returned an error: ${error}`);
})
}
When testing the new setup I indeed see a log message in the go server.
在测试新设置时,我确实在go服务器中看到一条日志消息。
go run main/server.go
Got the following url: freecodecamp.org
从Go调用屏幕截图API (Calling the screenshot API from Go)
Let's actually call the Screenshot API from our Go server.
让我们实际从Go服务器调用Screenshot API。
To begin I create a struct
that holds all the parameters needed to call the Screenshot API.
首先,我创建一个struct
,该struct
包含调用Screenshot API所需的所有参数。
type screenshotAPIRequest struct {
Token string `json:"token"`
Url string `json:"url"`
Output string `json:"output"`
Width int `json:"width"`
Height int `json:"height"`
ThumbnailWidth int `json:"thumbnail_width"`
}
Then, I update the thumbnailHandler
function to create a http POST request and call the API.
然后,我更新thumbnailHandler
函数以创建http POST请求并调用API。
func thumbnailHandler(w http.ResponseWriter, r *http.Request) {
var decoded thumbnailRequest
// Try to decode the request into the thumbnailRequest struct.
err := json.NewDecoder(r.Body).Decode(&decoded)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
// Create a struct with the parameters needed to call the ScreenshotAPI.
apiRequest := screenshotAPIRequest{
Token: "SCREENSHOTAPI_TOKEN",
Url: decoded.Url,
Output: "json",
Width: 1920,
Height: 1080,
ThumbnailWidth: 300,
}
// Convert the struct to a JSON string.
jsonString, err := json.Marshal(apiRequest)
checkError(err)
// Create a HTTP request.
req, err := http.NewRequest("POST", "https://screenshotapi.net/api/v1/screenshot", bytes.NewBuffer(jsonString))
req.Header.Set("Content-Type", "application/json")
// Execute the HTTP request.
client := &http.Client{}
response, err := client.Do(req)
checkError(err)
// Tell Go to close the response at the end of the function.
defer response.Body.Close();
// Read the raw response into a Go struct.
type screenshotAPIResponse struct {
Screenshot string `json"screenshot"`
}
var apiResponse screenshotAPIResponse
err = json.NewDecoder(response.Body).Decode(&apiResponse)
checkError(err)
// Pass back the screenshot URL to the frontend.
_, err = fmt.Fprintf(w, `{ "screenshot": "%s" }`, apiResponse.Screenshot)
checkError(err)
}
And when restarting the Go server you can see that the thumbnail generator still works! And as a bonus, nobody can steal our API token now.
重新启动Go服务器时,您会看到缩略图生成器仍然有效! 另外,现在没有人可以窃取我们的API令牌。
结论 (Conclusion)
We've set up a full-stack website thumbnail generator using Go and Vue. The frontend is separated from the backend and we've added an external API in the mix that we call from the Go server.
我们已经使用Go和Vue设置了完整的网站缩略图生成器。 前端与后端是分开的,并且我们在从Go服务器调用的混合中添加了一个外部API。
You can view the live version here and the Github source code here.
您可以在此处查看实时版本,并在此处查看Github源代码 。
Happy coding!
编码愉快!
翻译自: https://www.freecodecamp.org/news/how-i-set-up-a-real-world-project-with-go-and-vue/
使用vue3创建vue项目