본문 바로가기
개발/dart

10. Get Input from a Fom

by 허허 그림 2014. 3. 12.
728x90

이제 10장을 다 했습니다.

총 12장이니 이제 2장만 더 하면 되겠네요.

하지만 갈수록 내용이 많아지네요..

11장과 12장은 이번 10장보다 내용이 더 많은 듯 합니다..

3월안에 12장까지 끝낼 수 있을까.


참고: 오역과 오타가 많습니다. 그래서 원문과 함께 같이 볼 수 있도록 해놓았습니다. 혹시나 영어를 잘 하시는 분은 오역과 오타에 대해서 알려주시면 고맙겠습니다.


* 전체 링크

1.get started

2. Connect Dart & HTML

3. Add Elements to the DOM

4, Remove DOM Elements

- 5. Install Shared Packages

6. Define a Custom Element

7. Use Future-Based APIS

8. Use Streams for Data

9. Fetch Data Dynamically

10. Get Input from a Form

11. Use Indexed DB

12. Write Command-line Apps



Get Input from a Form
폼에서 input 값 가져오기

Use forms to get data from users.
사용자가 입력한 값을 가져오기 위해 form 이용하기

Many web applications rely on forms to collect data and submit that data to a server. A form usually contains several input elements for entering data of various kinds, such as names and addresses, birthdays, email addresses, and so on. HTML supports several kinds of input elements, including text fields, text areas, radio buttons, and checkboxes. HTML5 adds more specialized input elements such as email and password fields, color pickers, date and time widgets, and range elements.

많은 웹 어플리케이션은 데이터를 수집하고 서버에 데이터를 보내기 위해 form 에 의존하고 있습니다. form은 일반적으로 이름, 주소, 생일, 이메일 주소등과 같은 다양한 데이터를 입력받기 위해 몇개의 input 요소가 포함되어 있습니다.HTML은 텍스트 필드, 텍스트 에어리어, 라디오 버튼과 체크박스와 같은 몇가지 종류의 input 요소를 지원합니다. HTML5 는 이메일과 비밀번호 필드, 색상 선택기, 날짜와 시간 위젯과 범위 요소 같은 좀 더 특화된 input 요소를 추가했습니다.

The main example in this tutorial contains a client and a server. The client uses Polymer to present its user interface (a form with many kinds of input elements), and keep the interface in sync with Dart data. The client and server communicate using several classes from various Dart libraries, including streams, Futures, HttpRequest, and so on. The server uses CORS headers to allow cross-origin requests.

이번 튜토리얼의 메인 예제는 클라이언트와 서버가 포함되어 있습니다. 클라이언트는 사용자 인터페이스(많은 종류의 input 요소를 사용하는 form)를 나타내기 위해서 Polymer 를 사용합니다. 그리고 Dart 데이터와 동기화하는 인퍼페이스를 유지합니다. 클라이언트와 서버간에는 다양한 Dart 라이브러리에 있는 몇 가지 클래스를 사용해서 통신할 것입니다. 사용할 클래스는 stream, Futre, HttpRequest 와 같은 것들이 있습니다. 서버는 cross-orgin 요청을 허용할 수 있도록 CORS 헤더를 사용하고 있습니다.

Note: This tutorial assumes that you have read Define a Custom Element, Use Future-Based APIs, and Fetch Data Dynamically and are familiar with Polymer, Futures, JSON, and HttpRequest.

참고: 이번 튜토리얼은 당신이 Define a Custom Element, Use Future-Based APIsFetch Data Dynamically 을 읽었다고 가정하고 Polymer, Futures, JSON과 HttpRequest와 비슷합니다.

About forms, generally
form에 대해, 일반적인것들

A form has an action, which is a URL to which to send the form data, and a method, which indicates how the form data is to be sent. The action and the method can be specified declaratively within HTML, or for more complex situations or for more control, you can write Dart code and use Dart libraries to perform the action programmatically.

form 은 form 데이터를 전송하기 위한 URL인 액션이있고 form 데이터를 어떻게 보낼지에 대해 나타내는 메소드가 있습니다. 액션과 메소드는 HTML 에서 선언적으로 지정되어질 수 있습니다. 다른 방법으로는  좀 더 복잡한 상황이나  좀 더 세세한 컨트롤을 하기 위해서는, 프로그램에 따라서 그러한 복잡하고 자세한 컨트롤을 수행하기 위해서 Dart 코드와 Dart 라이브러리를 이용해서 작성할 수도 있습니다.

Let’s begin with a basic, HTML-only form to learn a little bit about action, method, input elements, and the default behavior of forms. The form below uses Google to search the website specified in the <form> tag if the checkbox is selected (or the web if it is not), for the text entered by the user. In this example, called search_form, the default is to search dartlang.org for “Cookbook”, a useful resource for learning about Dart.

액션, 메소드, input 요소와 form의 기본 동작에 대해 조금 배우기 위해 HTML용 form을 사용해서 기본적인 것에서부터 시작합니다. 아래에 있는 form (실제 실행 가능한 앱은 https://www.dartlang.org/docs/tutorials/forms/ 를 참조하세요.)은 , 만약 체크박스에 체크가 되어 있다면 사용자가 입력한 텍스트를  <form> 태그안에 명시된 웹사이트에서 찾기 위해서 Google을 사용합니다. 만약 체크가 되어 있지 않다면 전체 웹 사이트에서 찾습니다. search_form 이라고 하는 이번 예제에서, 디폴트는 dartlang.org에서 "Cookbook”를 찾습니다. 나온 검색 결과는 Dart에 대해 배우는데 유용한 정보들일 것입니다.

Here is the HTML code that creates the form:

form을 만드는 HTML 코드가 아래에 있습니다.

<form action="http://www.google.com/search"
     
method="GET"
     
target="_blank">
 ...
</form>

Of interest are the action and method attributes.

흥미로운점은  actionmethod 속성입니다.

Attribute

Description

action

The URL to which to send the request. In this example, the URL specifies a Google search. When the user clicks the button, search parameters are appended to this URL.
해당 요청을 보내게 될 URL, 이 URL은 Google 검색을 지정합니다. 사용자가 버튼을 클릭할때, 검색 파라미터는 이 URL에 덧붙여집니다.

method

How to send the request. In general, you should use GET to request data from a resource and POST to submit data to a server.
요정을 어떻게 보낼지에 대해 지정합니다. 일반적으로 자원에서 데이터를 요청하기 위해 GET을 사용하고 서버에 데이터를 보내기 위해 POST를 사용합니다.


And here is the HTML code that puts three input elements—a text field, a submit button, and a checkbox—into the form:
그리고 3개의 input 요소—텍스트 필드, 전송버튼, 체크박스—를 놓아두는 HTML 코드가 있습니다.

<input   type="text"     name="q"
                        
value="Cookbook" size="31" maxlength="255">
<input   type="submit"   value="Google Search">
<label>
 
<input type="checkbox" name="sitesearch"
                        
value="dartlang.org" checked> Search dartlang.org<br>
</label>

The checkbox is wrapped in a label so that you can click either the checkbox or the label to change the selection.

체크박스는 요소는 체크박스나 체크박스 옆의 텍스트(레이블)를 클릭했을때도 선택을 바꿀 수 있게 하기 위해 label 태그로 감싸져 있습니다.

This HTML code provides some automatic behaviors.

이 HTML 코드는 약간 자동적인 동작을 제공합니다.

<input type="submit" ...>

Creates a special button that when clicked, gathers the data from the form. Based on the action and method attributes, the button formulates the request and submits it to the server at the URL provided.

<input type=”submit”..> 태그는 클릭했을 때, form 에서 데이터를 가져올 수 있는 특별한 버튼을 만듭니다. 액션과 메소드 속성에 따라, 이 버튼은 요청을 만들어내고 제공된 URL의 서버에 그것을 보냅니다.

name="q"

name="sitesearch"

Specifies the name of the text field and the name of the checkbox.
이속성들은 텍스트 필드와 체크 박스의 이름을 지칭합니다.

Within a form, the input elements that have names provide the data for the form. In this example, the value of the text field provides the value for q, and the checkbox provides the value for sitesearch, both part of a valid Google search URL. The name and its value are appended to the search URL when the user clicks the submit button. For example,

http://www.google.com/search?q=Cookbook&sitesearch=dartlang.org

폼에서, 이름을 가지고 있는 input 요소는 form에 데이터를 제공합니다. 이 예제에서, 텍스트 필드의 값은 q 에 값을 제공하고 체크박스는 sitesearch 에 값을 제공합니다. 이 둘 다는 구글 검색 URL의 한 부분입니다. 사용자가 서브밋 버튼을 클릭했을때 이름과 값은 구글 검색 URL의 뒤에 붙습니다. 예를 들면 아래와 같은 모양입니다.

http://www.google.com/search?q=Cookbook&sitesearch=dartlang.org


The example is purely declarative with no Dart or JavaScript code. Because its simple, it can use the default HTML form behavior, a publicly available and easily formed URL, and a basic GET request. For forms that contain a lot of data, or for web applications that communicate with a specialized server, you usually need to handle forms programmatically.

이 예제는 Dart와 자바스크립트 코드가 없는 순수한 평문입니다. 이런 간단함 때문에, 공개적으로 사용가능하고 쉽게 형식화된 URL 그리고 기본적인 GET 요청을 기본적인 HTML 폼 작업에 사용할 수 있습니다. 많은 데이터를 가지고 있는 Form 이나 전용 서버와 통신을 해야 하는 웹 어플리케이션의 경우에는 일반적으로 프램그램적으로 form을 처리합니다.

The next example shows a more complex form that sends data to a server programmatically using a POST request.

다음 예제는 POST 요청을 사용해서 프로그램적으로 서버에 데이터를 보내는 좀 더 복잡 form 을 보여줍니다.

About the slambook example, specifically
slambook 예제에 대해, 구체적으로

The primary example in this tutorial consists of two programs.

이 튜토리얼의 주요 에제는 다음 2개 프로그램으로 구성되어 있습니다.

  • First, a basic server program, called slambookserver, listens on port 4040 on the local host and handles POST and OPTIONS requests by printing a message and sending a confirmation to the client. The server uses CORS headers to allow requests from applications running from a different origin.

  • 첫번째, slambookserver 이라고 하는 기본적인 서버 프로그램은 로컬호스트에서 4040포트에서 수신대기합니다. 그리고 메시지를 출력하고 클라이언트에게 확인을 보내는 POST와 OPTIONS 요청을 처리합니다. 이 서버는 다른 자원에서 실행중인 어플리케이션으로 부터의 요청을 허용하도록 CORS  헤더를 사용합니다.

  • Second, the client program, called slambook, provides a form into which users can enter some information. It uses Polymer two-way data binding to bind the input data to Dart variables. When the user clicks the submit button, the Dart code formats the data into a JSON string, sends an OPTIONS request to get permission from the server, and then a POST request to send the data. When the response from the server is ready, the client displays it.

  • 두번째, slambook 라고 하는 클라이언트 프로그램은 사용자가 어떤 정보를 입력할 수 있도록 하는 form을 제공합니다. 그것은 Dart 변수에 input 데이터를 바인딩 하기 위해 Polymer 양방향 데이터 바인딩을 사용합니다. 사용자가 서브밋 버튼을 클릭했을때, Dart 코드는 JSON 문자열로 데이터를 포맷하고, 서버로부터 허가를 얻기 위해 OPTIONS 요청을 보냅니다. 그리고 그 다음에 데이터를 보내기 위해 POST 요청을 보냅니다. 서버로 부터의 응답이 준비되면 클라이언트는 결과 데이터를 보여줍니다.

The following diagram shows the flow of communication between the server and the client in this example.

다음의 그림은 이 예제에서의 서버와 클라이언트간의 통신 흐름을 보여줍니다.


Client-server communication in the slambook example


Try it! Enter some data and push the Submit button.

시도해 보세요(실 사용 에제는 https://www.dartlang.org/docs/tutorials/forms/#about-the-slambook-example 에서 확인하세요) . 데이터를 넣고 서브밋 버튼을 누루세요.

Version Note: The slambook app is compatible with polymer.dart 0.9.

The request gives you an innocent stare and displays “No server” because you are not running the server on your machine. Let’s fix that.

버전 정보: slampbook 앱은 polymer.dart 0.9 와 호환됩니다.
이 요청은 당신에게 아무런 해가 없는(악의 없는) 답을 주고 "No server” 를 표시합니다. 왜냐하면 아직 당신의 컴퓨터에 서버를 실행하고 있지 않기 때문입니다. 한번 이걸 고쳐봅시다.

Run the server
서버 실행하기.

Get the source code for the basic server program, slambookserver.dart, from the tutorials samples  download.

Run the server program from the command line:

tutorials samples에서 slambookserver 의 기본적인 서버 프로그램 소스 코드를 다운 받으세요.

명령줄에서 서버 프로그램을 실행하세요.

% dart slambookserver.dart
Listening for GET and POST on http://127.0.0.1:4040

Now, you can try submitting data again with the slambook app above.

지금부터, 당신은 위에 있는 slambook 앱에서 다시 한번 데이터를 서브밋 해보세요.

Note: If another program is already listening on localhost 4040, the server prints an error message and quits. The app running on this page expects slambookserver to be at localhost 4040, so for the app to work, you have to kill the other process and start slambookserver again. Alternatively, you can change the port number in both the client and the server code. Avoid using 3030 because Dart Editor listens there. Then run both the client and the server locally on your machine.

참고: 다른 프로그램이 벌써 로컬호스트 4040 포트를 수신하고 있다면 이 서버는 에러 메시지를 출력하고 중지됩니다. 이 페이지에서 실행되고 있는 앱은 로컬호스트 4040 포트에 있는 slambookserver를 기대하고 있습니다. 이 앱이 정상 작동을 위해서 당신은 다른 프로세스를 죽여야 하고 slambookserver를 다시 한번 실행시키세요. 다른 방법으로, 클라이언트와 서버 코드의 포트 번호를 바꿀수도 있습니다. 그래도 Dart 에디터가 3030 포트 번호를 쓰고 있기 때문에 3030 포트 번호는 피해주세요. 그 후에 당신의 컴퓨터에 있는 로컬 클라이언트와 서버를 실행하세요.


The rest of this tutorial explains the code for both the client and the server.

이 튜토리얼의 나머지 부분에서는 클라이언트와 서버의 코드에 대해서 설명합니다.

On the client side, you learn about

클라이언트 쪽에서 당신이 아래의 것들에 대해서 배울 것입니다.

  • Submitting the form
    form 서브밋 하기.

  • Resetting the form
    form 리셋하기.

  • Using Polymer to bind the form data to variables in the Dart program
    Dart 프로그램에 있는 변수와 form 데이터를 바인딩하기 위해 Polymer 사용하기.

On the server side, the sections cover

서버쪽에서의 섹션은 아래와 같습니다.

  • CORS headers

  • CORS 헤더

  • Handling OPTIONS requests

  • OPTIONS 요청 처리하기

  • Handling POST requests

  • POST 요청 처리하기.

Submitting a form
form 서브밋 하기.

Let’s first take a look at how the data is submitted to the server.

자 먼저 데이터가 어떻게 서버에 서브밋 되어지는지 살펴봅시다.

Recall that the search_form example relies on the action and method attributes to set the destination and method for the form request. Recall also that the search_form example relies on the automatic behavior of the special submit button. The slambook example, on the other hand, takes explicit control of the form submission process.

search_form 예제는 form 요청에서 목적지와 메소드를 설정하기 위해서 action 와 method 속성에 의존하고 있다는 것을 상기하세요. 또한 search_form 예제는 특별한 서브밋 버튼을의 자동 기능에 의존하고 있다는 것도 상기하세요. 다른 한편으로, 이 slambook 예제는 form  전송 과정을 명시적으로 제어합니다.

  • First, the form specifies no action or method.
    첫번째, form 은 action 과 method를 지정하지 않는다.

  • Second, the submit button has a Dart mouse click handler.
    두번째, 전송버튼은 Dart 마우스 클릭 핸들러가 붙는다.

  • Third, the mouse click handler prevents the automatic behavior of the submit button.
    세번째, 마우스 클릭 핸들러는 전송버튼의 자동 작업을 막는다.

  • Finally, the form submits the data to the server with help from the Dart libraries.
    마지막으로, form 은 Dart 라이브러리의 도움을 받아 서버에 데이터를 전송한다.

The form in the slambook example is a custom element called tute-slambook-form that’s instantiated with this HTML code:

slambook 예제의 form은 tute-slambook-form  이라고 하는 사용자 요소이고 HTML 코드에서 인스턴스화 됩니다.

<div class="container">
 
<form is="tute-slambook-form" id="slambookform"></form>
</div>

Note the absence of either an action or a method attribute. Instead, the behavior for the submit button is coded in a Dart mouse click handler. Below is the HTML code that creates the submit button and binds it to a Dart mouse click handler.

action 이나 method 속성이 존재 하지 않는다는 점에 유의하세요. 대신에, 전송 버튼의 동작은 Dart 마우스 핸들러에 코딩되어 있습니다. 아래에 전송버튼을 만들고 Dart 마우스 클릭 핸드러를 그 전송버튼에 바인딩하는 HTML 코드가 있습니다.

<div class="submitarea">
 
<input type="submit" value="Submit" on-click="{{submitForm}}">
 ...
</div>

Here’s the code for the submitForm() mouse click handler:
여기에 마우스 클릭 핸들러인 submitForm() 함수의 코드가 있습니다.
Making a post request

Let’s walk through the click handler’s code.

이제 클릭 핸들러의 코드를 살펴봅시다.

Suppressing the default action
기본적인 동작 억제하기.

Even without an action and a method attribute, the submit button has some automatic behavior, which the slambook example does not need. So the first line of code in the mouse click handler calls e.preventDefault() to suppress the default behavior of the submit button.

action  와 method 속성이 없어도, 전송 버튼은 몇 가지 자동적인 행동을 합니다. 그러한 자동적인 행동은 slambook 예제에 필요가 없습니다. 그래서 마우스 클릭 핸들러 코드의 첫번째 라인은 전송버튼의 기본 행동을 억제(금지) 시키기 위해서  e.preventDefault() 를 호출합니다.

void submitForm(Event e) {
 e
.preventDefault(); // Don't do the default submit.
 
...
}

Setting up and making the POST request
POST 요청을 만들고 설정하기.

Next, the code creates an HttpRequest object. This code uses new to create an HttpRequest object, which needs to be configured to make a POST request. The HttpRequest class has a convenience function, getString(), that you can use to make a basic GET request on a URL.

다음은, 이 코드는 HttpRequest 객체를 생성합니다. 이 코드는 POST 요청을 하기위해 구성해야 하는   HttpRequest 객체를 만들기 위해 new 를 사용합니다.  HttpRequest  클래스는 URL의 기본적인 GET 요청을 하는데 사용할 수있는 편리한 함수인 getString() 를 가지고 있습니다.

The next line provides the HttpRequest object with a callback function, called onData, that gets invoked when the server responds. We’ll look at the implementation details for onData() later.

다음 라인은 서버가 응답할때 호출되는 onData 핸들러라고 하는 콜백 함수의 HttpRequest  객체를 제공합니다. 우리는 나중에 onData() 에 대해서 자세한 세부사항을 알아보겠습니다.

Important: You must register the callback function before making the request!

중요: 반드시 요청을 하기전에 콜백 함수를 등록 해야 합니다.

request = new HttpRequest();
request
.onReadyStateChange.listen(onData);

var url = 'http://127.0.0.1:4040';
request
.open('POST', url);
request
.send(slambookAsJsonData());

Next, the code opens a POST request with a URL specifying the port and host on which slambookserver is listening.

다음은, 이 코드는 slambookserver가 수신하고 있는 포트와 호스트를 지정하는 URL을 사용하여 POST 요청을 엽니다.

Finally, the function sends the form data as a JSON string to the server. Sometimes, the data is streamed in chunks. But in this example, the data is short enough that all of the data is sent at once. This request is asynchronous, so the send() method returns as soon as the request is sent.

마ㅣ막으로, 이 함수는  서버에 JSON 문자열로 데어터를 만들어서 전송합니다. 경우에 따라서는 이 데이터는 큰 덩어리로 스트리밍됩니다. 그러나 이번 예제에서는, 이 데이터는 한번에 전송되기에 충분히 작습니다. 이 요청은 비동기이므로 send() 메소드는 요청이 보내진 즉시 리턴됩니다.

Listening for the server response
서버 응답 수신하기.

The HttpRequest object handles communication with the server. You can get the state of that communication through the HttpRequest object’s readyState field. The ready state has five possible values: unsent, opened, headers received, loading, and done. When the ready state changes, HttpRequest fires an event, and the onData() callback function gets called.

HttpRequest 객체는 서버와의 통신을 처리합니다. 당신은 HttpRequest 객체의 readyState  필드를 통해 통신 상태를 얻을 수 있습니다. 준비 상태는 5개의 가능한 값이 있습니다.  unsent, opened, headers received, loading 그리고 done 이 있습니다. 준비 상태가 바뀔때 HttpRequest 는 이벤트를 발생시키고 onData() 콜백함수가 호출 됩니다.

Recall the line of code that registers onData as a listener on the onReadyStateChange event stream:

onReadyStateChange 에 리스너로 onData 콜백함수를 등록한 코드를 상기하세요.

request.onReadyStateChange.listen(onData);

The only required argument to the listen() method is a callback function with this signature: void onData(T). The listen() method also lets you specify three optional arguments, such as an error handler.

listen() 메소드에 단 하나의 필수 인자는 다음의 모습을 가지는 콜백 함수 입니다. void onData(T). listen() 메소드에 또한 error 핸들러 같은, 당신이 3개의 부가적인 인자를 지정할수도 있습니다.

The onData() callback function is straightforward:

onData() 콜백 함수는 복잡하지 않습니다.

void onData(_) {
 
if (request.readyState == HttpRequest.DONE &&
     request
.status == 200) {
   
// Data saved OK.
   serverResponse
= 'Server Sez: ' + request.responseText;
 
} else if (request.readyState == HttpRequest.DONE &&
     request
.status == 0) {
   
// Status is 0...most likely the server isn't running.
   serverResponse
= 'No server';
 
}
}

First the code checks whether the request is complete and successful. If it is, the code puts the server’s response in a string, called serverResponse, which is bound to the value of a textarea in the slambook app’s UI. When the string changes, the UI is automatically updated, and the message is displayed for the user.

첫번째 코드는 요청이 완료가 되고 성공이었는지를 체크합니다. 만약 그렇다면, 이 코드는 serverResponse 라고 하는 문자열 변수에 서버의 응답을 집어넣습니다. 이 serverResponse  변수는 slambokk 앱 UI에 있는 텍스트에어리어의 값과 바인딩됩니다. 문자열이 바뀔때, 이 UI는 자동적으로 업데이트가 되고 메시지는 사용자에게 보여지게 됩니다.

If the request is complete but unsuccessful, the program sets serverResponse to an error message, thus displaying it to the user.

요청이 완료는 되었지만 실패했다면, 프로그램은 에러 메시지를 serverResponse 에 세팅하고 사용자에게 그 에러 메시지를 보여줍니다.

Resetting a form
form 리셋하기.

The reset button is a special HTML input type that, by default, clears the values of all inputs within the form. Instead, we want the button to reset the values in the form to their initial value. So, the mouse click handler for the reset button needs to suppress the automatic behavior and reset the form with neutral data explicitly.

리셋버튼은 기본적으로 form에 있는 모든 input에 있는 값을 지워버리는 특별한 HTML input 타입입니다. 대신에, 우리는 폼에 있는 값이 초기값으로 리셋되는 버튼을 원합니다. 따라서, 리셋 버튼의 마우스 클릭 핸들러는 자동 동작을 막고 명시적으로 중립적인 데이터를 폼에 리셋합니다.

void resetForm(Event e) {
 e
.preventDefault();
 favoriteThings
['kittens'] = false;
 favoriteThings
['raindrops'] = false;
 favoriteThings
['mittens'] = false;
 favoriteThings
['kettles'] = false;

 theData
['firstName'] = '';
 theData
['favoriteQuote'] = '';
 theData
['favoriteColor'] = '#FFFFFF';
 theData
['birthday'] = '2013-01-01';
 theData
['volume'] = '0';
 theData
['catOrDog'] = 'cat';
 theData
['music'] = 0;
 theData
['zombies'] = false;
 serverResponse
= "Data reset.";
}

Creating a server and listening on a port
서버를 만들고 포트 수신하기.

Let’s turn our attention now to the server, called slambookserver, that responds to HTTP requests from the slambook client. The code for the server is based on the one in Chris Buckett’s article Using Dart with JSON Web Services.

그럼 이제, slambook  클라이어튼에서 HTTP 요청에 응답하는 slambookserver 이라고 하는 서버쪽을 한 번 살펴봅시다.서버 코드는 Chris Buckett 의 문서인  Using Dart with JSON Web Services 의 하나를 기초로 합니다.

The server listens on port 4040 on the local host and handles only POST and OPTIONS requests. For both types of requests, the server adds CORS headers to allow access. For POST requests, the server returns a short confirmation message that includes the JSON data it received in the request.

서버는 로컬 호스트 4040 포트를 수신하고 POST와 OPTIONS  요청만을 처리합니다. 이 2개 타입의 요청 경우에, 서버가 접근할수 있도록 CORS 헤더를 추가합니다. POSt 요청의 경우에는, 서버는 요청받은 JSON 데이터를 포함하는 짧은 확인 메시지를 리턴합니다.

Let’s take a look at the code.

코드를 한 번 봅시다.

Below is the entire main() function for slambookserver. Using the HttpServer class, slambookserver starts listening on port 4040 on the local host by calling the top-level bind() function.

아래에는 slambookserver의 전체 main() 함수가 있습니다. HttpServer 클래스를 사용하는 slambookserver은  최상위 bind() 함수를 호출함으로써 로컬 호스트 4040 포트를 수신을 시작하고 있습니다.

final HOST = '127.0.0.1';
final PORT = 4040;

void main() {
 HttpServer
.bind(HOST, PORT).then(gotMessage, onError: printError);
}

The bind() function returns a Future object, which is a way to get a value in the future (more about that in a minute). Using then(), the code registers two callback functions on the Future. The first, gotMessage(), is called when the Future returns its value. The second, printError, is called if the binding fails. An error might occur if, for example, another program is already listening on the same port.

bind() 함수는 미래의 값(몇 분 후)을 가져오는 방법인 Future 객체를 리턴합니다. then() 사용하면, 코드는 Future 에 2개의 콜백함수를 등록합니다.두번째는, 바인딩이 실패했을 경에  printError 가 호출되어집니다. 예를 들어, 다른 프로그램이 이미 같은 포트를 사용하고 있을 경우와 같이 에러는 발생할 수 있습니다.

The code for gotMessage(), shown below, filters the request and calls other methods to handle each specific kind of request.

아래에 보이는 getMessage() 함수 코드는 요청을필터링하고 요청의 종류에 맞게 처리하기 위한 각 각 다른 메소드를 호출하고 있습니다.

void gotMessage(_server) {
 _server
.listen((HttpRequest request) {
   
switch (request.method) {
     
case 'POST':
       handlePost
(request);
       
break;
     
case 'OPTIONS':
       handleOptions
(request);
       
break;
     
default: defaultHandler(request);
   
}
 
},
 onError
: printError); // Listen failed.
 print
('Listening for GET and POST on http://$HOST:$PORT');
}

To handle other types of requests such as GET requests, you could simply add more case statements, such as case 'GET'.

Get 요청과 같은 다른 종류의 요청을 처리하기 위해서는  case 'GET' 과 같은 case 문을 간단히 좀 더 추가할 수 있습니다.

About Futures, briefly
간단히 Future에 대해서

Let’s take a brief look at Futures before we check out the code for handling OPTIONS and POST requests.

OPTIONS와 POST 요청에 대해서 알아보기 전에 Future에 대해서 간단히 살펴 봅시다.

A Future represents a way to get a value sometime in the Future. You use Futures to avoid blocking the program while waiting for a value—for example, if the value requires a long time to compute, or if the value must be read or retrieved using I/O.

Future 는 앞으로 언젠가는 미래의 값을 가져오는 방법을 나탑니다. 가지고 올려고 하는 값이 계산하는데 오래걸리거나 반드시 모두 다 읽혀져야 된다거나 또는 I/O를 사용하여 검색을 하는 경우와 같이 값을 가져 오는데 기다리는 동안 프로그램이 중지되는 것을 피하기 위해 Future 를 사용합니다.

When a function that returns a Future is invoked, two things happen:

Future 를 리턴하는 함수가 실행될때 2가지 일이 일어납니다.

  • The function queues up work to be done and returns an uncompleted Future object immediately.

  • 그 함수는 수행할 작업을 큐(대기열)에 넣고 완료되지 않은 Future 를 리턴합니다.

  • Later, when the value is available, the Future object completes with that value or with an error.

  • 나중에, 값이 사용가능해 졌을때, 그 Future  객체는 그 값을 가지고 작업을 완료하꺼나 에러를 냅니다.

To get the value that the Future represents, use the then() method to register a callback. When the Future completes, it calls the callback function.

Future가 나타내는 값을 얻기 위해서는, 콜백 함수를 등록하는 then() 메소드를 사용하세요. Future 가 완료될때, 그것은 콜백함수를 호출합니다.

In this example, both the client and server use Futures when sending requests and responses back and forth. Client-server programs should almost always handle communication and other forms of I/O asynchronously with Futures.

이 예제에서, 클라이언트와 서버 둘 다는 요청을 보내고 앞 뒤로 응답할때  Future 를 사용합니다. 클라이언트-서버 프로그램은 대부분의 경우에 Future를 사용해서 비동기적으로 통신과 다른 형태의 I/O를 처리합니다.

Handling OPTIONS requests
OPTIONS 요청 처리하기.

With help from the HttpRequest class, the slambook client makes a POST request when the user clicks the submit button. You saw the code for this earlier in this tutorial.

HttpRequest 클래스의 도음으로, slambook  클라이언트는 사용자가 전송버튼을 클랙했을때 POST 요청을 수행합니다. 당신은 이번 튜토리얼의 앞에서 이 코드를 봤습니다.

If the client is running from a different origin than the server, which is common in web apps, the POST request is “preflighted”. A preflighted request must first send an OPTIONS request to determine if the actual request is allowed. The HttpRequest class automatically handles the preflight OPTIONS request. You do not have to write the client-side code for that.

클라이언트가 웹 앱에 공통되는 서버와 다른 기원에서 실행되는 경우에, 그 POST 요청은 "preflighted”가 됩니다. preflighted 요청은 반드시 실제 요구가 허락되었는지를 확인하기 위해  OPTIONS 요청을 먼저 보내야 합니다. HttpRequest 클래스는 자동적으로 이 preflighted  OPTIONS  을 처리합니다.따라서 당신은 클라이언트 쪽 코드에 이걸 위한 코드를 작성할 필요가 없습니다.

The server gets the OPTIONS request before it gets the preflighted request. Here’s the slambookserver code that handles OPTIONS requests.

서버는 preflighted 요청을 받기 전에 OPTION 요청을 가져옵니다. 여기에 OPTIONS 요청을 처리하는 slambookserver 코드가 있습니다.

void handleOptions(HttpRequest req) {
 HttpResponse res
= req.response;
 addCorsHeaders
(res);
 print
('${req.method}: ${req.uri.path}');
 res
.statusCode = HttpStatus.NO_CONTENT;
 res
.close();
}

The code is straightforward:

이 코드는 간단합니다.

  • Get the HttpResponse object, which carries the server’s response to the client.

  • 클라이언트에 서버의 응답을 전달하는 HttpResponse 객체를 얻으세요.

  • Add CORS headers to set access control

  • 접근 컨트롤을 설정하기 위해 CORS 헤더를 추가하세요.

  • Print a message to the console

  • 콘솔에 메시지를 출력하세요.

  • Indicate that the response has no content

  • 응답에는 내용이 없다른 것을 나타냅니다.

  • Close the response, thus sending the response to the client.

  • 응답을 닫으세요. 따라서 클라이언트에 응답을 보냅니다.

When the client gets the response, the CORS headers indicate that a POST request would be accepted.

클라이언트가 응답을 받을때, 그 CORS 헤더는 POST 요청이 받아들여졌다고 인식합니다.

Setting CORS headers
CORS 헤더 세팅하기.

The server uses the following function to add CORS headers to its response to both OPTIONS and POST requests. The function adds three Access-Control headers to the server’s response (contained in an HttpResponse object).

서버는 OPTIONS 와 POSt 요청 둘다의 응답에 CORS 헤더를 추가하기 위해서 다음의 함수를 사용합니다.이 함수는 서버의 응답에(HttpResponse 객체를 포함하는 ) 3개의 접근 컨트롤 헤더를 추가합니다.

void addCorsHeaders(HttpResponse res) {
 res
.headers.add('Access-Control-Allow-Origin', '*, ');
 res
.headers.add('Access-Control-Allow-Methods', 'POST, OPTIONS');
 res
.headers.add('Access-Control-Allow-Headers',
     
'Origin, X-Requested-With, Content-Type, Accept');
}

Together, the first two CORS headers allow POST and OPTIONS requests from any origin. The third specifies the kind of POST and OPTIONS requests the server accepts by specifying the headers that it allows.

함께 처음 2개의 CORS 헤더는 어떤 기원에서의 POST 와 OPTIONS 요청을 허용합니다. 3번째는 서버가 허락하는 헤더를 지정함으로서 받아 들일 수 있는 POST와 OPTIONS의 종류를 지정합니다.


For more information about CORS refer to:

CORS에 대해서 좀 더 많은 정보를 원한다면 아래의 링크를 참조하세요.

Handling POST requests
POST 요청 처리하기.

Here is the function that handles the client’s HTTP POST request:

여기에 클라이언트의 HTTP POST요청을 처리하는 함수가 있습니다.

void handlePost(HttpRequest req) {
 HttpResponse res
= req.response;
 print
('${req.method}: ${req.uri.path}');

 addCorsHeaders
(res);

 req
.listen((List<int> buffer) {
   
// Return the data back to the client.
   res
.write('Thanks for the data. This is what I heard you say: ');
   res
.write(new String.fromCharCodes(buffer));
   res
.close();
 
},
 onError
: printError);
}

As with the OPTIONS request, slambookserver gets the HTTP response object from the request, prints a message to the console, and adds the CORS headers to the response.

OPTION 요청과 마찬가지로, slambookserver은 request 로 부터 HTTP response 객체를 얻고, 콘솔에 메시지를 출력하고, response 객체에 CORS 헤더를 추가합니다.

Next the code listens for the data from the client’s POST request. When all the data is ready, the callback function gets called. The callback function is written in place as a function literal. The argument to the function, a list of integers, contains all of the data. Each integer is a character code, which can be a UTF-16 code unit or rune. You don’t need to worry about this, because you can just use the String.fromCharCodes() method to convert the list of character codes into a normal string.

다음 코드는 클라이언트의 POST 요청에서 데이터를 수신대기합니다. 모든 데이터가 준비가 되면 , 콜백함수가 호출됩니다. 이 콜백함수는 함수 리터럴 형식으로 작성되어져 있습니다. 함수의 인자인 숫자형 배열을 모든 데이터를 포함하고 있습니다. 각각의 숫자는 문자 코드입니다. 그것은 UTF-16 코드 값이나 문자일 수 있습니다. 당신은 이것에 대해서 걱정할 필요가 없습니다. 왜냐하면 이 문자코드의배열을 정상적인 문자열로 바꾸기 위해서 그냥 String.fromCharCodes() 메소드를 사용하면 됩니다.

The HttpResponse object manages a data stream that the server can use to send data back to the client. Within the data callback function, slambookserver writes a message and the original data as a string to that stream. A more sophisticated server would do something with the data, such as save it on the server, process it, and maybe remove funds from your bank account.

HttpResponse 객체는 서버가 클라이언트에게 다시 데이터를 전송하기위해 사용할 수 있는  데이터 스트림을 관리합니다.데이터 콜백 함수에서, slambookserver은 그 스트림에서 문자열로  메시지와 원본 데이터를 작성합니다.좀 더 정교한 서버는 서버에 데이터를 저장 한다거나 처리하거나 하는 다른 작업을 할 수 있습니다. 그리고 어쩌면 당신의 은행계좌에서 자산을 삭제할 일지도 모르지요..

Upon closing the stream, the HttpResponse object sends the data to the client.

스트림을 닫으면, HttpResponse 객체는 클라이언트에게 해당 데이터를 보냅니다.

Recipe for client-server web apps
클라이언트-서버 웹 앱의 설계도

The slambook client-server example can serve as a starting point for your client-server web apps or as a recipe for building your own.

slambook 클라이언트-서버 예제는 클라이언트-서버 웹 앱을 위한 출발점이나 직접 구축하기 위한 설계도로써 역할을 할 수 있습니다.

Here’s an outline of what the client needs to do.

클라이언트가 무엇을 해야 하는지에 대한 개요입니다.

  • Use forms to gather data from a user.

  • 사용자로부터 데이터를 얻기 위해 form 을 이용하세요.

  • Put input fields in your forms for individual data items.

  • 각 데이터 아이템을 위해 form에 input 필드를 넣으세요.

  • Use Polymer two-way binding to keep the form data in sync with the Dart code.

  • Dart 코드와 동기화하여 form 데이터를 유지하기 위해 Polymer 양방향 바인딩을 사용하세요.

  • Send data declaratively (action and method attributes on the form)

  • 선언적으로(form에 있는 action 과 method 속성을 이용해서) 데이터를 전송하세요.

  • … or programmatically (overriding the default behavior of the submit button with Dart code)

  • 또는 프로그램적으로(Dart 코드를 이용해서 전송 버튼의 기본적인 작동을 오버라이딩해서) 데이터를 전송하세요.

  • Get the response from the server from the HttpRequest object.

  • HttpRequest 객체에서 서버의 response 을 얻으세요.

  • Handle communication asynchronously with a Future object.

  • Future 객체를 이용해서 비동기적으로 통신을 처리하세요.

And, here’s what the server needs to do.

그리고 서버에서 해야할 작업들이 있습니다.

  • Use HttpServer to set up a server to listen on a port and host.

  • 포트와 호스트를 수신하는 서버를 설정하기 위해 HttpServer를 사용하세요.

  • Listen for requests.

  • 요청을 수신하세요.

  • Use CORS headers to set access permissions for each request.

  • 각각의 요청에 대한 접근 허락을 설정하기 위해 CORS 헤더를 사용하세요.

  • Respond to requests using HttpResponse.

  • HttpResponse를 사용해서 요청에 응답하세요.

  • Handle communication asynchronously with Futures.

  • Future를 사용하여 비동기적으로 통신을 처리하세요.

  • Use streams to write the response data.

  • 응답 데이터를 쓰기 위해 스트림을 사용하세요.

These resources, mostly from the core Dart libraries, provide support for writing clients and servers. Note that there are two HttpRequest classes, one in dart:html (for clients) and one in dart:io (for servers).

대부분 핵심 Dart 라이브러리에 있는 이러한 자원들은 클라이언트와 서버 프로그램을 작성하는데 도움을 제공합니다. 클라이언트에서 쓰는 dart:html 에 있는 HttpRequest 클래스와 서버에서 쓰는 dart:io에 있는 HttpRequest 클래스가 있다는 것을 참고하세요.

Resource

Library

Description

HttpRequest

dart:html

Client-side HTTP request
클라이언트 쪽 HTTP 요청

HttpRequest

dart:io

Server-side HTTP request
서버쪽 HTTP 요청

HttpServer

dart:io

Server-side object to handle HTTP communication with clients
클라이언트와의 HTTP 통신을 처리하기 위한 서버쪽 객체

HttpResponse

dart:io

Server-side object to carry response to client requests
클라이언트 요청에 응답을 싣기 위한 서버쪽 객체

Streams

dart:async

A stream of data
데이터의 스트림

Future

dart:async

A way to get a value asynchronously
비동기적으로 값을 얻기 위한 방법

JSON

dart:convert

The default implementation of a JSON converter
JSON 변환기의 기본 구현 클래스

Polymer

Polymer

Custom elements, data binding, templates
사용자 요소, 데이터 바인딩, 템플릿 제공

Two-way data binding using Polymer
Polymer를 사용한 양방향 데이터 바인딩

The slambook sample uses Polymer’s two-way data binding to bind the values of input elements to Dart variables. If the user changes the value in an input element, the bound variable in the Dart code automatically changes. Or if the Dart code changes the value of the bound variable, the UI automatically updates. Define a Custom Element provides introductory details about Polymer and about data binding.

slambook 샘플은 Dart 변수에 input 요소의 값을 바인드 하기 위해 Polymer의 양방향 데이터 바인딩을 사용합니다. 사용자가 input 요소에서 값을 바꾼다면, Dart 코드에 그 input 요소와 바인딩된 변수도 자동으로 바뀝니다. 또한 Dart 코드에서 바인딩된 변수의 값이 바뀐다면, UI는 자동으로 업데이트 됩니다. Define a Custom Element 은 Polymer과 데이터 바인딩에 대해서 기조척인 정보를 제공합니다.

The example also uses declarative event handler mapping to hook event handler functions to input elements.

또한, 이 예제는 input 요소에 이벤트 핸들러 함수를 연결하는 선언적 이벤트 핸들러를 사용합니다.

With the slambook example, you can see two-way data binding used with a variety of input elements, including new HTML5 elements. This table summarizes the two-way data binding attributes you can use with Polymer:

slmabook 예제에서, 새로운 HTML5 요소를 포함하는 다양한 input 요소에 쓰여진 양방향 데이터 바인딩을 보실 수 있습니다. 아래의 테이블은 Polymer에서 사용될 수 있는 양방향 데이터 바인딩을 요약해 놓았습니다.


Attribute

Dart type

Input element

value

String

any

selectedIndex

integer

a <select> element in which only one choice is allowed

하나만 선택할 수 있는 <select> 요소

checked

bool

individual radio buttons or checkboxes

라디오 버튼이나 체크 박스 각각에

Using value with any input element
모든 input 요소에 value 사용하기.

The value attribute works with any input element and binds the value to a Dart string. This example uses value with a text field, a text area, a color picker, a date chooser, and a range element.

value 속성은 모든 input 요소에 작동이 가능하고 Dart 문자열에 그 값을 바인딩할 수 있습니다. 이 예제에서는 텍스트 필드, 텍스트 에어리어, 색깔 선택기, 날짜 선택기 그리고 범위 요소에 value 를 사용하고 있습니다.Two-way data binding with value and strings

(Note that some surrounding code, such as that for the labels, has been removed for readability.)

(lable에 대한 것들과 같은 주변 코드들은 가독성을 위해서 제거되었다는 것을 참고하세요.)

A map called theData in the Dart code contains the data for the form. The code marks the map object with @observable and calls toObservable() to make the bindings.

Dart 코드에서 theData 라고 하는 map 은 form 의 데이터를 가지고 있습니다. 이 코드는 @observable 를 가지고 map 객체에 표시를 하고 데이터 바딩을 하기 위해서 toObservable() 를 호출합니다.

The map contains a key-value pair for each input element, where the key is a string. The values for elements bound with value are all strings. The HTML refers to the items in the map using their Dart names (identifiers). For example, the value of the color picker is bound to theData['favoriteColor'].

이 맵 객체는 각 각의 input 요소에 대해서 키는 문자열인 키-값의 쌍을 가지고 있습니다. value에 바인딩된 요소의 값들은 모두 문자열입니다. HTML은 그것들의 Dart 이름(식별자)를 사용하여 맵의 항목을 참조합니다. 예를들면, 색상 선택기의 값은 theData['favoriteColor'] 에 바인딩되어 있습니다.

Using selectedIndex with a pull-down menu
풀 다운 메뉴에서 selectedIndex 사용하기.

A <select> element contains one or more <option> elements, only one of which, by default, can be selected at a time. A single-select element is usually implemented as a pull-down menu. You can use the selectedIndex attribute to bind a Dart integer to a pull-down menu. The integer indicates the index of the selected item. Indices begin at 0.

<select> 요소는 하나 또는 그 이상의 <option> 요소를 가지고 있습니다. 기본적으로 한번에  그 <option> 중에 단 하나만을 선택할 수 있죠.  이런 single-select 요소는 보통 풀 다운 메뉴에 사용되어 집니다. 당신은 풀 다운 메뉴에 Dart 숫자형을 바인딩하기 위해 selectedIndex 속성을 사용할 수 있습니다.이 숫자형은 select 항목의 인덱스를 가르치고 있습니다. 인덱스는 0부터 시작합니다.The selectedIndex attribute with a single-selection pull-down menu

Using checked with checkboxes
checkbox 에서 checked 사용하기.

You can use the checked attribute to bind a Dart boolean to a single checkbox. Here each checkbox is bound to a separate boolean value within a map.

단일 체크박스에 Dart 부울 값을 바인딩하기 위해 checked 속성을 사용할 수 있습니다. 여기에 각 각의 체크박스는 map 객체에서  각각의 부울 값과 바인딩 되었습니다.The checked attribute with individual checkboxes

Other resources
다른 자원들

  • The code that handles the communication between the client and server is based on code written and explained by Chris Buckett in Using Dart with JSON Web Services.

  • 클라이언트와 서버간의 통신을 처리하는 코드는 Chris Buckett가 쓴 Using Dart with JSON Web Services에서 설명하고 쓰여진 코드에 기초로 했습니다.

  • The previous tutorial, Fetch Data Dynamically, contains a more basic client program that relies on the server within Dart Editor (port 3030 on localhost), to serve the contents of a JSON file.

  • 이전의 튜토리얼인 Fetch Data Dynamically 은 JSON 파일의 내용을 제공하기 위해,  Dart 에디터로 만들어진(로컬호스트의 포트 3030을 이용하는) 서버에 의존하는 좀 더 기본적인 클라이언트 프로그램을 포함하고 있습니다.

What next?
다음은?

The next tutorial, Use IndexedDB, describes how to save data on the client in the browser’s Indexed Database.

다음 튜토리얼인 이것에서는 브라우저의 indexed Database에 클라이언트의 데이터를 어떻게 저장하는지에 대해서 설명할 것입니다.


300x250

'개발 > dart' 카테고리의 다른 글

12. Write Command-Line Apps  (0) 2014.03.17
11, Use Indexed DB  (0) 2014.03.14
9. Fetch Data Dynamically  (0) 2014.03.04
8. Use Streams for Data  (0) 2014.03.02
7. Use Future-Based APIs  (0) 2014.03.02

댓글