File upload and download is a very common function in Web application development. Basically every project has to be developed again, very wordy not to say, its performance is not very good, the function is not powerful.

Speaking of our own application is ali Cloud OSS service, feel very good, so in order to save trouble in the future, we decided to use Golang to develop a file server based on HTTP, providing similar services.

The service currently only performs simple file upload and access functions. In the next few months, we plan to gradually improve richer functions, such as file deduplication, image processing, subcontracting path, etc. Basically, we hope to reference the functions of oss and other cloud storage services.

During this period, we also experienced many pits, which are recorded as follows:

  • Http File upload
  • Static file access
  • Ajax cross-domain upload
  • Golang cross-compile

The problems and solutions encountered in this development are listed below.

Code :(where the ftpbootstrap. go file in the ftpCommand directory is the service initiator, and the file with the same name is the linux-x64 compiled executable file)

Github


Http File upload

HTTP uploads are of course the most basic feature. For the sake of web applications, uploads are based on the multipart/form-data form of the form.

File, handler, err := r.vormfile ()"file")
	iferr ! = nil { var response = UploadResponse{State: -1, Msg: err.Error(), URL:""}
		response.Send(w)
		return} // File extension fileext := filepath.ext (handler.filename) // Use timestamp as Filename to prevent the same name Filename := strconv.formatint (time.now ().unix (), F, _ := os.openFile ("./upload/"+ filename, OS. O_CREATE | OS. O_WRONLY, 0660) _ / / save the file, err = IO. Copy (f, file)Copy the code

It looks like Golang is much easier to save files than Java. The BUILT-IN I/O tools are very convenient.

You need to give a return message after uploading the file. Using Json as the return format, we define the structure as follows:

UploadResponse returns a messagetype UploadResponse struct {
	State int    `json:"state"`
	URL   string `json:"data"`
	Msg   string `json:"msg"`}Copy the code

It is important to note that Golang is sensitive to formatting conventions, and to convert this structure to Json, only capitalized fields can be converted to Json. You didn’t notice this at first, and as a result, the converted Json remains empty. For a long time. The following JSON :” MSG “and other remarks can specify the field name to convert to.

The resulting Json result from such a structure is as follows:

{
  "state": 0."data": "/get/1476696601.png"."msg": "success"
}
Copy the code

Static file access

After the file has been successfully uploaded, it is the access function. Golang FileServer is used here.

http.Handle("/get/", http.FileServer(httpDir))
Copy the code

When I started writing it this way, it didn’t work. After some trying and searching, the following is correct:

http.Handle("/get/", http.StripPrefix("/get/", http.FileServer(httpDir)))
Copy the code

There is an http.stripprefix method. The function of this method is to subtract the specified route. In this case, the “/get/” at the beginning of the request is subtracted. This allows FileServer to access the file correctly through the specified path.


###Ajax cross-domain upload

This is a front-end problem. The original code uses Jsonp to implement Ajax cross-domain requests. However, Jsonp itself is a third-party convention, and it does not support POST requests. FormData data cannot be uploaded through POST.

With materials on the web, you can use the latest XHR2 for cross-domain access. Very simple and convenient, unfortunately only support IE10 above, but no matter ah! This must be the trend of history!

The key to implementing cross-domain requests through XHR2 is the addition of several headers:

  • Access-Control-Allow-Origin
  • Access-Control-Allow-Methods
  • Access-Control-Allow-Headers

The first specifies the domain name to allow cross-domain access, the second specifies the access method, and the third specifies the accepted Header.

Since there is only one interface at present, it is written in the interface for uploading files first. In principle, it should be extracted and processed uniformly.

//w define by w http.ResponseWriter
	w.Header().Set("Access-Control-Allow-Origin"."*")
	w.Header().Set("Access-Control-Allow-Methods"."POST, GET, OPTIONS, PUT, DELETE")
	w.Header().Set("Access-Control-Allow-Headers"."Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
	w.Header().Set("Content-Type"."application/json")
Copy the code

The last Content-Type is also necessary, otherwise the browser will not treat the returned data as JSON.

Specifying access-Control-allow-Origin as * is dangerous. This allows access to all domains. On a temporary basis as a test service. The domain name must be specified in specific applications.


Golang cross-compile

Cross compilation is one of Golang’s cool features. Golang itself doesn’t support a one-place build, run everywhere cross-platform approach, but it’s really handy for cross-compiling.

The information on the Internet is not very fresh, many of the methods in the information also need to be re-compiled with source code and so on. In the latest version of Golang, these tedious steps are no longer needed, and cross-compilation is done with a single command:

GOOS=linux GOARCH=amd64 go build bootstrap.go
Copy the code

GOOS specifies the operating system, most commonly Darwin (macOS), Windows, and Linux. GOARCH is the platform, which supports AMD64,386, and ARM, but arm support is said to be incomplete.

In addition, the GOARCH parameter can be omitted if the target platform is the same as the current platform.

By cross-compiling, I could develop on my Macbook, package it up as an executable, and throw it on a Linux server to boot, easy and quick. It’s just so much better than Java’s plethora of supporting environments.