카테고리 보관물: HTTP 웹 Study

[W5500-EVB Project] Easy Web Server

This project is using the W5500-EVB and operating embedded web server Plese check the below picture Embedded web server

First, You Look for Desription Sequential Flow chart (Block Diagram)

Sequence = HTTP Request Parser -> HTTP GET Method -> Requested Web content Found -> Load the Web content from storage -> HTTP Response HTTP/1.1 200 OK + HTTP body -> Send HTTP Response.
Second,This project Use to HTTP Protocol based and HTTP header GET Method. But Not Used POST, PUT, HEAD etc.. header
For more information about Hypertext Transfer Protocol please also refer to the Wiki page
HTTP is Configuration to Server / Client.
– HTTP Server : Embedded device(W5500-EVB)
– HTTP Client : Web browser (Internet Explore, Chrome etc..)
Web server is operating for HTTP based.
Request to Web server from Web browser -> Web server is Transport to response message to web browser(web page)
This project is Not Using Javascript & JSON. Just Using C & HTML Language. It is vey simply source code.

그림1123 This project is Not Using Javascript & JSON. Just Using C & HTML Language. It is vey simply source code


/*
===============================================================================
 Name        : W5500EVB.c
 Author      : $(author)
 Version     :
 Copyright   : $(copyright)
 Description : main definition
===============================================================================
*/

#if defined (__USE_LPCOPEN)
#if defined(NO_BOARD_LIB)
#include "chip.h"
#else
#include "board.h"
#endif
#endif

#include "spiHandler.h"
#include "w5500_init.h"
#include "common.h"
#include "loopback.h"
#include "mmcHandler.h"
#include "dataflashHandler.h"
#include "wizchip_conf.h"
#include "ffconf.h"
#include "eepromHandler.h"
#include "ftpc.h"
#include 

// TODO: insert other include files here


// TODO: insert other definitions and declarations here

typedef struct __Cfg_Info {
	uint8_t spiflash_flag[2];
} __attribute__((packed)) Cfg_Info;

/*****************************************************************************
 * Private types/enumerations/variables
 ****************************************************************************/
#define TICKRATE_HZ1 (1000)		/* 1000 ticks per second, for SysTick */
#define TICKRATE_HZ2 (1)		/* 1 ticks per second, for Timer0 */
volatile uint32_t msTicks; 		/* counts 1ms timeTicks */

/*****************************************************************************
 * Public types/enumerations/variables
 ****************************************************************************/
///////////////////////////////////////
// Debugging Message Printout enable //
///////////////////////////////////////
#define _MAIN_DEBUG_

///////////////////////////
// Demo Firmware Version //
///////////////////////////
#define VER_H		1
#define VER_L		00

#define POTENTIOMETER_CH				ADC_CH0		// ADC channel for on-board Potentiometer (ADC channel / Pin shared with Temperature sensor)
#define POTENTIOMETER_ADC_PORT_NUM		0
#define POTENTIOMETER_ADC_PIN_NUM		11

#define ADC_READ_PERIOD_MS				10			// ms

static ADC_CLOCK_SETUP_T 				ADCSetup;
static bool ADC_read_enable = false;

//////////////////////////////////////////////////
// Socket & Port number definition for Examples //
//////////////////////////////////////////////////
#define SOCK_TCPS       0
#define SOCK_UDPS       1
#define SOCK_WEBSERVER	1
#define PORT_TCPS		5000
#define PORT_UDPS       3000
#define PORT_WEBSERVER	80
/* for Web Server test debug message printout enable */
#define	_WEBSERVER_DEBUG_
#define	WEBSERVER
#define WEBSERVER_EX	1 // mode setting
/************************/
/* Select Web Server_MODE */
/************************/

#define LED_BLUE 					Chip_GPIO_ReadPortBit(LPC_GPIO, 1, 24)
////////////////////////////////////////////////
// Shared Buffer Definition for LOOPBACK TEST //
////////////////////////////////////////////////

uint8_t gDATABUF[DATA_BUF_SIZE];
uint8_t gFTPBUF[_MAX_SS];
//uint8_t LED_G = Chip_GPIO_ReadPortBit(LPC_GPIO, 1, 23);
///////////////////////////
// Network Configuration //
///////////////////////////
wiz_NetInfo gWIZNETINFO = { .mac = {0x00, 0x08, 0xdc, 0xab, 0xcd, 0xef},
                            .ip = {192, 168, 10, 111},
                            .sn = {255, 255, 255, 0},
                            .gw = {192, 168, 10, 1},
                            .dns = {8, 8, 8, 8},
                            .dhcp = NETINFO_STATIC };

// For TCP client loopback examples; destination network info
uint8_t destip[4] = {192, 168, 10, 230};
uint16_t destport = 5000;

int g_mkfs_done = 0;
int g_sdcard_done = 0;

////////////////////
// Button Control //
////////////////////
#define BUTTONS_PRESSED_TICKS		10		// ms
bool button1_enable = false;
bool button1_pressed_flag = false;

uint8_t send_dat[1024]={0,};
uint16_t dataADC;
static void Init_ADC_PinMux(void)
{
 	Chip_IOCON_PinMuxSet(LPC_IOCON, POTENTIOMETER_ADC_PORT_NUM, POTENTIOMETER_ADC_PIN_NUM, FUNC2);
}


static void display_SDcard_Info(uint8_t mount_ret);
static uint8_t Check_Buttons_Pressed(void);
void SysTick_Handler(void);
/* Web Server test example */
int32_t WebServer(uint8_t sn, uint8_t* buf, uint16_t port);
char proc_http(uint8_t sn, char * buf);
void sendHeader(uint8_t sn);
void sendData(uint8_t sn);
uint16_t calcu_len(void);
int main(void) {
	uint8_t ret = 0;
    //int32_t loopback_ret;
	//uint16_t dataADC;
	uint16_t previous_dataADC = 0;

#if defined (__USE_LPCOPEN)
#if !defined(NO_BOARD_LIB)
    // Read clock settings and update SystemCoreClock variable
    SystemCoreClockUpdate();
    // Set up and initialize all required blocks and
    // functions related to the board hardware
    Board_Init();
    // Set the LED to the state of "On"
    //Board_LED_Set(0, true); //GREEN
    //Board_LED_Set(1, true);		//BLUE
    Board_LED_Set(2, false);			//RED
#endif
#endif

	SPI_Init();
	W5500_Init();
	Net_Conf(gWIZNETINFO);

#ifdef _MAIN_DEBUG_
	uint8_t tmpstr[6] = {0,};

	ctlwizchip(CW_GET_ID,(void*)tmpstr);
/*
    printf("\r\n=======================================\r\n");
	printf(" WIZnet %s EVB Demos v%d.%.2d\r\n", tmpstr, VER_H, VER_L);
	printf("=======================================\r\n");
	printf(">> W5500 based FTP Client Example\r\n");
	printf("=======================================\r\n");
*/
	Display_Net_Conf(); // Print out the network information to serial terminal
#endif

	/* Enable and setup SysTick Timer at a periodic rate */
	SysTick_Config(SystemCoreClock / TICKRATE_HZ1);

	/* Initialize buttons on the W5500 EVB board */
	Board_Buttons_Init();
	/* ADC Init */
	Init_ADC_PinMux();
	Chip_ADC_Init(LPC_ADC, &ADCSetup);
	Chip_ADC_EnableChannel(LPC_ADC, POTENTIOMETER_CH, ENABLE);

	g_sdcard_done = 0;

#if defined(F_APP_FTPC)
	ftpc_init(gWIZNETINFO.ip);
#endif

	ret = flash_mount();
	if(ret > 0)
	{
		display_SDcard_Info(ret);
	}

	while(1) {
		if(ADC_read_enable){
			ADC_read_enable = false;
			/* Start A/D conversion */
			Chip_ADC_SetStartMode(LPC_ADC, ADC_START_NOW, ADC_TRIGGERMODE_RISING);
			/* Waiting for A/D conversion complete */
			while (Chip_ADC_ReadStatus(LPC_ADC, POTENTIOMETER_CH, ADC_DR_DONE_STAT) != SET) {}
			/* Read ADC value */
			Chip_ADC_ReadValue(LPC_ADC, POTENTIOMETER_CH, &dataADC);
		}
		//if(previous_dataADC != dataADC)
		if((previous_dataADC/10) != (dataADC/10)){
			previous_dataADC = dataADC;
			/* Print ADC value */
			printf("Read Potentiometer value is %d\r\n", dataADC);
		}

	   	/* Button: SW1 */
		if(Check_Buttons_Pressed() == BUTTONS_BUTTON1)
		{
			printf("\r\n########## SW1 was pressed.\r\n");
			printf("########## Data flash flag was cleared.\r\n");
			printf("########## Please reset a target.\r\n");
			release_factory_flag();
		}

#if defined(F_APP_FTPC)
		ftpc_run(gFTPBUF);
#endif
#if	defined(WEBSERVER)
		WebServer(SOCK_WEBSERVER, gDATABUF, PORT_WEBSERVER);
#endif
		/* Loopback Test: TCP Server and UDP */
		// Test for Ethernet data transfer validation
		{
			//loopback_tcps(SOCK_TCPS, gDATABUF, PORT_TCPS);
			//loopback_udps(SOCK_UDPS, gDATABUF, PORT_UDPS);
			//loopback_ret = loopback_tcpc(SOCK_TCPS, gDATABUF, destip, destport);

			//if(loopback_ret < 0) printf("loopback ret: %ld\r\n", loopback_ret); // TCP Socket Error code
		}
	}

    return 0 ;
}

static uint8_t Check_Buttons_Pressed(void)
{
	static uint8_t buttons_status;
	static uint8_t ret;

	buttons_status = Buttons_GetStatus();

	if((buttons_status & BUTTONS_BUTTON1) == BUTTONS_BUTTON1) button1_enable = true; // button pressed check timer enable
	else button1_enable = false;

	if(button1_pressed_flag)	// button1 pressed (Specified time elapsed, enabled by sysTick_Handler function)
	{
		button1_pressed_flag = false; // pressed button clear
		ret = BUTTONS_BUTTON1; // return pressed button status
	}
	else
	{
		ret = 0;
	}

	return ret;
}

void SysTick_Handler(void)
{
	static uint16_t button1_pressed_check_cnt = 0;
	static bool button1_press_detected = false;

	msTicks++; // increment counter

	if (msTicks % ADC_READ_PERIOD_MS == 0) ADC_read_enable = true;
	// Button1 control
	if(button1_enable == true)
	{
		if(!button1_press_detected)
		{
			button1_pressed_check_cnt++;
			if(button1_pressed_check_cnt >= BUTTONS_PRESSED_TICKS)
			{
				button1_pressed_flag = true;
				button1_pressed_check_cnt = 0;
				button1_enable = false;

				button1_press_detected = true;
			}
		}
	}
	else
	{
		button1_pressed_check_cnt = 0;
		button1_press_detected = false;
	}
}

int32_t WebServer(uint8_t sn, uint8_t* buf, uint16_t port)
{
   int32_t ret;
   uint16_t size = 0, sentsize=0, i=10000;
#ifdef _WEBSERVER_DEBUG_
   uint8_t destip[4];
   uint16_t destport;
#endif

   switch(getSn_SR(sn))
   {
      case SOCK_ESTABLISHED :
         if(getSn_IR(sn) & Sn_IR_CON)
         {
#ifdef _WEBSERVER_DEBUG_
			getSn_DIPR(sn, destip);
			destport = getSn_DPORT(sn);

			printf("%d:Connected - %d.%d.%d.%d : %d\r\n",sn, destip[0], destip[1], destip[2], destip[3], destport);
#endif
			setSn_IR(sn,Sn_IR_CON);
         }
         while(i){
        	 i--;
         }
		 if((size = getSn_RX_RSR(sn)) > 0) // Don't need to check SOCKERR_BUSY because it doesn't not occur.
         {
			if(size > DATA_BUF_SIZE) size = DATA_BUF_SIZE;
			ret = recv(sn, buf, size);

			if(ret <= 0) return ret;      // check SOCKERR_BUSY & SOCKERR_XXX. For showing the occurrence of SOCKERR_BUSY.
			sentsize = 0;

			printf("HTTP Request received: \r\n%s\r\n", buf);
			proc_http(sn, (char *)buf);

         }
         break;
      case SOCK_CLOSE_WAIT :
#ifdef _WEBSERVER_DEBUG_
         printf("%d:CloseWait\r\n",sn);
#endif
         if((ret = disconnect(sn)) != SOCK_OK) return ret;
#ifdef _WEBSERVER_DEBUG_
         printf("%d:Socket Closed\r\n", sn);
#endif
         break;
      case SOCK_INIT :
#ifdef _WEBSERVER_DEBUG_
    	 printf("%d:Listen, Web Server, port [%d]\r\n", sn, port);
#endif
         if( (ret = listen(sn)) != SOCK_OK) return ret;
         break;
      case SOCK_CLOSED:
#ifdef _WEBSERVER_DEBUG_
         printf("%d:Web Server start\r\n",sn);
#endif
         if((ret = socket(sn, Sn_MR_TCP, port, 0x00)) != sn) return ret;
#ifdef _WEBSERVER_DEBUG_
         printf("%d:Socket opened\r\n",sn);
#endif
         break;
      default:
         break;
   }
   return 1;
}
void sendHeader(uint8_t sn)
{
	uint8_t dat[128]={0,};
	uint8_t dat_t[128]={0,};
	uint8_t *dat_temp;
	dat_temp = "HTTP/1.1 200 OK\r\n";						strcat(dat, dat_temp);
	dat_temp = "Content-Type: text/html\r\n";					strcat(dat, dat_temp);
	dat_temp = "Connection: close\r\n";						strcat(dat, dat_temp);
	sprintf(dat, "%sContent-Length: %d", dat, calcu_len());
	dat_temp = "\r\n\r\n";								strcat(dat, dat_temp);
	send(sn, (uint8_t *)dat, strlen(dat));
	printf("%s", dat);
}
uint16_t calcu_len(void)
{
	uint8_t *dat_temp;
	char * forbidden = NULL;
	unsigned char str[4]={0,};
#if	WEBSERVER_EX==1
	dat_temp = "\r\n";												strcat(send_dat, dat_temp);
	dat_temp = "\r\n";													strcat(send_dat, dat_temp);
	dat_temp = "\r\n";														strcat(send_dat, dat_temp);
	dat_temp = "\r\n";													strcat(send_dat, dat_temp);
	dat_temp = "\r\n";					strcat(send_dat, dat_temp);
	dat_temp = "W5500-EVB WebServer Test!!\r\n";									strcat(send_dat, dat_temp);
	dat_temp = "\r\n";								strcat(send_dat, dat_temp);
	dat_temp = "\r\n";													strcat(send_dat, dat_temp);
	dat_temp = "\r\n";														strcat(send_dat, dat_temp);
	dat_temp = "\r\n";				strcat(send_dat, dat_temp);
	dat_temp = "
W5500-EVB WebServer Test!!
\r\n";										strcat(send_dat, dat_temp);
	dat_temp = "

\r\n";													strcat(send_dat, dat_temp);
	dat_temp = "</pre>
<form name="\&quot;form1\&quot;">\r\n";												strcat(send_dat, dat_temp);
	if(!LED_BLUE){
		dat_temp = "
<input name="\&quot;do\&quot;" type="\&quot;hidden\&quot;" value="\&quot;ON\&quot;" />
\r\n";						strcat(send_dat, dat_temp);
		dat_temp = "
LED BLUE <input name="\&quot;formbutton1\&quot;" type="\&quot;button\&quot;" value="\&quot;ON\&quot;" />
\r\n";	strcat(send_dat, dat_temp);
	}
	else{
		dat_temp = "
<input name="\&quot;do\&quot;" type="\&quot;hidden\&quot;" value="\&quot;OFF\&quot;" />
\r\n";						strcat(send_dat, dat_temp);
		dat_temp = "
LED BLUE <input name="\&quot;formbutton1\&quot;" type="\&quot;button\&quot;" value="\&quot;OFF\&quot;" />
\r\n";	strcat(send_dat, dat_temp);
	}
	dat_temp = "</form>
<pre>\r\n";													strcat(send_dat, dat_temp);
	dat_temp = "

\r\n";													strcat(send_dat, dat_temp);
	dat_temp = "\r\n";													strcat(send_dat, dat_temp);
	dat_temp = "\r\n";														strcat(send_dat, dat_temp);
	dat_temp = "\r\n";													strcat(send_dat, dat_temp);
#endif
#if	WEBSERVER_EX==2
	dat_temp = "\r\n\r\n";														strcat(send_dat, dat_temp);
	dat_temp = "\r\n";													strcat(send_dat, dat_temp);
	dat_temp = "\r\n\r\n";														strcat(send_dat, dat_temp);
	dat_temp = "\r\n";													strcat(send_dat, dat_temp);
	dat_temp = "\r\n";				        strcat(send_dat, dat_temp);
	dat_temp = "W5500-EVB WebServer Test!!\r\n";									strcat(send_dat, dat_temp);
	dat_temp = "\r\n";								strcat(send_dat, dat_temp);
	dat_temp = "\r\n";													strcat(send_dat, dat_temp);
	dat_temp = "\r\n";														strcat(send_dat, dat_temp);
	dat_temp = "\r\n";	                        strcat(send_dat, dat_temp);
	dat_temp = "
W5500-EVB WebServer Test!!
\r\n";										strcat(send_dat, dat_temp);
	dat_temp = "

\r\n";													strcat(send_dat, dat_temp);
	dat_temp = "
Read Potentiometer = $$$$
\r\n";										strcat(send_dat, dat_temp);
	dat_temp = "\r\n";													strcat(send_dat, dat_temp);
	dat_temp = "\r\n";														strcat(send_dat, dat_temp);
	dat_temp = "\r\n";													strcat(send_dat, dat_temp);
	forbidden = strstr(send_dat, "$$$$");
	memset(forbidden,0,4);
	sprintf((char*)str, "%d", dataADC);
	memcpy(forbidden,str,4);
#endif
	return strlen(send_dat);
}
void sendData(uint8_t sn)
{
	uint16_t i;
	send(sn, (uint8_t *)send_dat, strlen(send_dat));
	printf("%s", send_dat);
	for(i=0;i<1024;i++){
		send_dat[i]=0;
	}
}
char proc_http(uint8_t sn, char * buf)
{
	if((buf[0]=='G')&&(buf[1]=='E')&&(buf[2]=='T')&&(buf[3]==' ')){ // GET_Request
		if((buf[5]=='?')){
			if((buf[9]=='O')&&(buf[10]=='N')){
				Board_LED_Set(2, false);
				sendHeader(sn);
				sendData(sn);
			}
			else{
				Board_LED_Set(2, true);
				sendHeader(sn);
				sendData(sn);
			}
		}
		else{
			sendHeader(sn);
			sendData(sn);
		}
	}

	return 1;
}



Advertisements

GET과 POST의 차이

다들 아시다시피 GET과 POST는 HTTP프로토콜을 이용해서 서버에 무언가를 전달할 때 사용하는 방식입니다. 웹개발자라면 당연히 알고 있어야 하는 사항이고 이걸 모르면 웹개발자체를 할 수가 없습니다. 상당히 기초적인 부분이긴 한데 잘 모르시는 분들도 있고 해서 미루고 미루던 포스팅을 이제야 합니다. ㅎㅎ GET과 POST 얘기를 하니까 예전 생각이 납니다. 예전이라고 해봤자 불과 2년밖에 되지 않았군요. 졸업을 앞두고 어떤 회사에 면접을 봤었는데 거기 이사님이 저에게 GET과 POST의 차이점이 뭐냐고 물었었는데 전 그땐 그게 무슨말인지도 몰랐죠. 떨어진 이유가 아마 그거이지 싶네요.. ㅎㅎㅎ(지금 생각하면 창피하군요)

어쨌든 처음 웹개발을 하게 되면 한번쯤은 생각하게 되는 문제 입니다. GET과 POST는 머가 다를까…. 하는…. 저도 처음엔 이게 상당히 궁금했습니다. 흔히 얘기하는GET과 POST의 차이는 다음과 같습니다.(배울때 당시 이해하던 수준정도로만 적습니다.)

  • GET은 주소줄에 값이 ?뒤에 쌍으로 이어붙고 POST는 숨겨져서(body안에) 보내진다.
  • GET은 URL에 이어붙기 때문에 길이제한이 있어서 많은양의 데이터는 보내기 어렵고 POST는 많은 양의 보내기에도 적합하다.(역시 용량제한은 있지만)
  • http://url/bbslist.html?id=5&pagenum=2 같이 하는 것이 GET방식이고 form을 이용해서 submit을 하는 형태가 POST입니다.

처음 배울때 배운건 이정도뿐이었던 것 같습니다. 위 내용은 맞는말이긴 하지만 이로썬 해결안되는 문제가 있습니다. 그건 언제 GET을 쓰고 언제 POST를 써야 하는가에 대한 문제였습니다. 이건 신입일때 꽤 오랫동안 생각하고 있었던 문제이기도 하는데 딱히 가르쳐 주는 곳은 없었습니다. 지금와서 보면 책에 이에 대해 나와있는 책들이 상당히 많이 있습니다만 웹표준에서도 그러하듯이 현업의 개발에서는 “원래의 목적에 맞게 기술을 사용하고 있는가?”에 대해서는 크게 관심이 없고 “어떤 기술이든 기능을 구현할 수 있는가?”에만 관심을 가지는 것이 전반적으로 깔려있기 때문에이런 부분에 대해서 관심을 가지는 개발자는 빈도수로 봤을때 그리 많지 않은 듯 합니다. 어쨌든 쉽게 말하면 클라이언트에서 서버로 데이터를 전송하려면 GET 아니면 POST밖에 없습니다.(사실 HTTP에는 PUT, DELETE등등 몇가지 더 있지만 그건 이글의 범주에서 벗어나서 언급하지 않습니다. 사실은 잘 몰라서 ㅡ..ㅡ HTTP 1.1 스펙참조)

id를 넘겨서 게시판의 리스트를 가져온다고 하면 당연히 GET을 쓸 것이고 글을 작성한다고 하면 POST를 작성하는 것이 일반적입니다. 전달해야 될 양이 많을 경우에는 고민없이 POST를 쓰게 되지만 양이 많지 않은 경우에는 GET도 되고 POST도 되기 때문에 고민이 시작됩니다. GET을 써야하나 POST를 써야하나. GET을 쓰면 URL이 깔끔해 지는 효과도 있기 때문에 작은 양을 여러개 전달해야 할 경우에는 POST를 써야하는가 하는 고민을 하게됩니다.(상당히 명백한 차이인듯 하면서 실제로 개발하다보면 고민하게 되는 경우가 좀 있더군요. 저만 그런지 모르겠지만…)


Image by dbking via Flickr

여기서 위의 언급한 차이점 외에 GET과 POST의 중요한 개념이 있습니다.

GET은 가져오는 것이고 POST는 수행하는 것입니다.

이 개념만 잘 생각하고 있으면 상황에 따라서 어느정도 선택을 할 수 있습니다.(물론 그래도 좀 고민되는 예외상황들은 있게 마련이죠.) 좀 자세히 설명하면 GET은 Select적인 성향을 가지고 있습니다. GET은 서버에서 어떤 데이터를 가져와서 보여준다거나 하는 용도이지 서버의 값이나 상태등을 바꾸지 않습니다. 게시판의 리스트라던지 글보기 기능 같은 것이 이에 해당하죠.(방문자의 로그를 남긴다거나 글읽은 횟수를 올려준다거나 하는건 예외입니다.) 반면에 POST는 서버의 값이나 상태를 바꾸기 위해서 사용합니다. 글쓰기를 하면 글의 내용이 디비에 저장이 되고 수정을 하면 디비값이 수정이 되죠. 이럴 경우에 POST를 사용합니다.

이 얘기를 하면 어느곳에서곤 반드시 예시로 나오는 것이 Google의 Accelerator 사건입니다.(대표적으로 예를 들게 이거밖에 없나봅니다. 항상 거론되는걸 보면…) Accelerator라는 것은 그이름대로 웹서핑의 속도를 향상시킬 목적으로 구글이 발표한 것이었습니다. 어떤 웹사이트에 갔을때 페이지에 있는 URL등을 Accelerator가 미리 모두 클릭해봐서 사용자가 해당 URL로 이동하기 전에 이미지등의 미리 받아놓을 수 있는 것들을 받아놓는 역할을 해서 웹서핑의 체감속도를 높여주는 것이 목적이었습니다. 캐시때문에 한번 방문한 사이트는 더 빨리 뜨는 것을 이용한 것이죠.

구글러들은 위에서 언급한 GET과 POST의 개념을 확실히 이해하고 이를 당연하다고 생각하는 사람들이었을 테니 이것이 문제가 될꺼라고는 전혀 생각지 못한듯 합니다. 하지만 현실은 그렇지 않죠. 실제 많은 개발자들은 GET과 POST를 용도구분없이 혼용해서 사용했고 Delete같은 곳에도 GET방식을 편의대로 이용한 것입니다. Accelerator는 이것을 구분하지 못하니 URL만 보였다 싶으면 냅다 클릭을 해댄 것이고 사용자가 클립한 것이 아닌 Bot이 직접 URL로 접근해버리자 해당 데이터들은 Delete를 수행해버려서 메일이나 게시글이 마구 지워지는 사태가 발생하였습니다. 좋은 의도였는데 상당히 안좋은 결과가 되었죠. 우리가 모두 이걸 지켰다면 훨씬 좋은 웹 환경이 됐을 텐데요.

그리고 가져오는 곳에 GET을 사용해야 하는 이유가 하나 더 있습니다. 얼마전에도 관련해서 포스팅한 적이 있지만 웹의 핵심이라고 할 수 있는 Link문제입니다. 기본적으로 웹에서 모든 리소스는 Link할 수 있는 URL을 가지고 있어야 합니다.(퍼머링크(permalink)1퍼머링크라면 더 좋겠지만 꼭 퍼머링크가 아니라고 하더라도) 그래야 Link를 할 수 있으니까요. 쉽게 말하면 어떤 페이지를 보고 있을때 다른 사람한테 그 주소를 주기 위해서 주소창의 URL을 복사해서 줄 수 있어야 한다는 것입니다. POST를 할 결우에는 값이 내부적으로 전달되기 때문에 URL만 전달할 수 없죠. 글을 저장하는 경우에는 URL을 제공할 필요가 없기 때문에 POST를 해도 상관이 없는 것이고요.

다른 것들에서도 그렇듯이 GET과 POST도 그냥 만들어진 것이 아니기 때문에 스펙에 정의된 용도대로 사용한다면 위에 언급한대로 부가적으로 얻을 수 있는 이익이 많이 있고 전체 웹을 생각해도 올바르다고 생각합니다.

  1. 는 인터넷에서 특정 페이지의 고유한 URL 주소를 뜻한다. 이 주소는 어떤 상황에도 관계없이 항상 동일한 내용을 가지는 페이지로 링크된다는 의미에서, 고유(permanent)한 주소라는 뜻의 permanent link를 줄여 만든 말이다. 한국어로 고유링크, 고유주소 등으로 부르기도 한다. – Wikipedia 발췌 – [Back]