HTTP 서버 사용하기

이재홍 http://www.pyrasis.com 2014.12.17 ~ 2015.02.07

요즘 나오는 Node.js 같은 플랫폼(언어)들은 기본 라이브러리만 가지고 HTTP 서버를 만들 수 있습니다. Go 언어도 기본 패키지만으로 HTTP 서버를 간단하게 만들 수 있습니다.

다음은 net/http 패키지에서 제공하는 HTTP 함수입니다.

  • func ListenAndServe(addr string, handler Handler) error: HTTP 연결을 받고, 요청에 응답
  • func HandleFunc(pattern string, handler func(ResponseWriter, *Request)): 경로별로 요청을 처리할 핸들러 함수를 등록
  • func Handle(pattern string, handler Handler): 경로별로 요청을 처리할 핸들러 등록
  • func FileServer(root FileSystem) Handler: 파일 서버 핸들러
  • func StripPrefix(prefix string, h Handler) Handler: HTTP 요청 경로에서 특정 문자열을 제거합니다. 예) /assets/hello.js → hello.js
  • func NewServeMux() *ServeMux: HTTP 요청 멀티플렉서 인스턴스 생성

먼저 간단하게 Hello, world!를 출력해보겠습니다.

package main

import (
	"net/http"
)

func main() {
	http.HandleFunc("/", func(res http.ResponseWriter, req *http.Request) {
		res.Write([]byte("Hello, world!")) // 웹 브라우저에 응답
	}) // / 경로에 접속했을 때 실행할 함수 설정

	http.ListenAndServe(":80", nil) // 80번 포트에서 웹 서버 실행
}

http.HandleFunc에 URL 하위 경로와 해당 경로를 처리할 함수를 설정해줍니다. 여기서는 최상위 경로인 ”/”를 설정했으므로 웹 브라우저에서 / 경로에 접속했을 때 두 번째 매개변수에 들어가있는 함수가 실행됩니다. 그리고 res.Write 함수에 “Hello, world!”를 넣어서 웹 브라우저에 문자열을 표시할 수 있습니다.

http.ListenAndServe 함수에 포트 번호를 지정하여 웹 서버를 실행합니다. 앞에서 핸들러를 설정했으므로 두 번째 매개변수는 nil로 설정합니다.

소스 파일을 컴파일하여 실행한 뒤 웹 브라우저로 http://127.0.0.1에 접속해보면 “Hello, world!” 문자열이 표시될 것입니다.

이번에는 http.ListenAndServe 함수에 핸들러를 넣어서 웹 서버를 실행해보겠습니다.

package main

import (
	"net/http"
)

func main() {
	mux := http.NewServeMux() // HTTP 요청 멀티플렉서 생성

	mux.HandleFunc("/", func(res http.ResponseWriter, req *http.Request) {
		res.Write([]byte("Hello, world!")) // 웹 브라우저에 응답
	})

	http.ListenAndServe(":80", mux) // 80번 포트에 웹 서버를 실행하고, mux를 이용하여 HTTP 요청을 처리
}

먼저 http.NewServeMux 함수로 HTTP 요청 멀티플렉서(multiplexer) 인스턴스를 생성합니다. HTTP 요청 멀티플렉서는 URL 경로를 동시에 여러 개를 처리한다고 하여 멀티플렉서라 부릅니다(앞에서 사용한 http.HandleFunc 함수도 내부적으로는 http.NewServeMuxDefaultServeMux 인스턴스를 생성하여 사용하므로 완전히 같은 기능입니다).

HTTP 요청 멀티플렉서 인스턴스의 HandleFunc 함수에서 URL 하위 경로와 해당 경로를 처리할 함수를 설정해주면 됩니다. 사용 방법은 앞의 http.HandleFunc 함수와 같습니다.

이번에는 Hello, world! 문자열에 CSS로 색상을 설정하고, 경고 창을 출력하는 웹 서버를 만들어보겠습니다. 다음 내용을 GOPATH/src/httpserver/httpserver.go 파일로 저장합니다. GOPATH를 설정하는 방법은 ‘Unit 3 기본 디렉터리 설정하기’를 참조하기 바랍니다.

GOPATH/src/httpserver/httpserver.go

package main

import (
	"net/http"
)

func main() {
	s := "Hello, world!"

	http.HandleFunc("/", func(res http.ResponseWriter, req *http.Request) {
		// HTML로 웹 페이지 작성
		html := `
		<html>
		<head>
			<title>Hello</title>
			<script type="text/javascript" src="/assets/hello.js"></script>
			<link href="/assets/hello.css" rel="stylesheet" />
		</head>
		<body>
			<span class="hello">` + s + `</span>
		</body>
		</html>
		`

		res.Header().Set("Content-Type", "text/html") // HTML 헤더 설정
		res.Write([]byte(html))                       // 웹 브라우저에 응답
	})

	http.Handle(              // /assets/ 경로에 접근했을 때
                                  // 파일 서버를 동작시킴
		"/assets/",
		http.StripPrefix( // 파일 서버를 실행할 때 assets
                                  // 디렉터리를 지정했으므로 URL 경로에서 /assets/ 삭제
			"/assets/",
			http.FileServer(http.Dir("assets")), // 웹 서버에서 assets
                                                             // 디렉터리 아래의 파일을 표시
		),
	)

	http.ListenAndServe(":80", nil) // 80번 포트에서 웹 서버 실행
}

다음 내용을 GOPATH/src/httpserver/assets/hello.js, GOPATH/src/httpserver/assets/hello.css 파일로 저장합니다.

GOPATH/src/httpserver/assets/hello.js

alert('Hello, world!')

GOPATH/src/httpserver/assets/hello.css

.hello {
  font-size: 20px;
  color: red;
}

http.HandleFunc에 URL 하위 경로와 해당 경로를 처리할 함수를 설정해줍니다.

http.HandleFunc("/", func(res http.ResponseWriter, req *http.Request) {
	// HTML로 웹 페이지 작성
	html := `
	<html>
	<head>
		<title>Hello</title>
		<script type="text/javascript" src="/assets/hello.js"></script>
		<link href="/assets/hello.css" rel="stylesheet" />
	</head>
	<body>
		<span class="hello">` + s + `</span>
	</body>
	</html>
	`

	res.Header().Set("Content-Type", "text/html") // HTML 헤더 설정
	res.Write([]byte(html))                       // 웹 브라우저에 응답
})

함수의 매개변수 req에는 웹 브라우저가 접속했을 때의 메서드(GET, POST, PUT, DELETE 등), 쿠키, 헤더 등이 들어있고, res로 웹 브라우저에 응답을 해줄 수 있습니다. 여기서는 웹 브라우저가 / 경로에 접속하면 HTML을 만들어서 Write 함수로 응답해줍니다. 그리고 res.Header().Set(“Content-Type”, “text/html”)처럼 현재 경로의 헤더 값도 정해줍니다.

방금 GOPATH/src/httpserver/assets 디렉터리 아래에 hello.js, hello.css 파일을 저장했습니다. 웹 서버에서 이 파일을 보여줄 수 있도록 핸들러를 설정해줍니다.

http.Handle(              // /assets/ 경로에 접근했을 때
                          // 파일 서버를 동작시킴
	"/assets/",
	http.StripPrefix( // 파일 서버를 실행할 때 assets
                          // 디렉터리를 지정했으므로 URL 경로에서 /assets/ 삭제
		"/assets/",
		http.FileServer(http.Dir("assets")), // 웹 서버에서 assets
                                                     // 디렉터리 아래의 파일을 표시
	),
)

http.Handle 함수에 URL 하위 경로인 /assets/를 설정해주고, http.FileServer, http.Dir 함수에 assets 디렉터리를 지정합니다. 단, http.Dir 함수에 assets 디렉터리를 설정했으므로 웹 서버 입장에서 hello.js 파일은 /assets/hello.js가 아닌 hello.js로 접근해야 합니다. 따라서 http.StripPrefix 함수로 /assets/ 경로를 삭제해줍니다(/assets/hello.js → ./hello.js)

http.ListenAndServe 함수에 포트 번호를 지정하여 웹 서버를 실행합니다. 여기서는 http.NewServeMux 함수로 HTTP 요청 멀티플렉서 인스턴스를 생성하지 않고, http.HandleFunc, http.Handle로 요청을 처리할 핸들러를 설정했으므로 두 번째 매개변수는 nil로 설정합니다.

http.ListenAndServe(":80", nil) // 80번 포트에서 웹 서버 실행

이제 소스 파일을 컴파일하여 실행한 뒤 웹 브라우저로 http://127.0.0.1에 접속합니다.


그림 58-1 HTTP 웹 서버에 접속

HTTP 웹 서버에 접속하면 붉은색으로 된 Hello, world!와 경고 창이 출력될 것입니다.


저작권 안내

이 웹사이트에 게시된 모든 글의 무단 복제 및 도용을 금지합니다.
  • 블로그, 게시판 등에 퍼가는 것을 금지합니다.
  • 비공개 포스트에 퍼가는 것을 금지합니다.
  • 글 내용, 그림을 발췌 및 요약하는 것을 금지합니다.
  • 링크 및 SNS 공유는 허용합니다.

Published

01 June 2015