Aug 04 2008

ASP로 AJAX & Cross Domain 해결하기

분류: Tip.Tech 태그: ,, , Heart @ 10:34 오후

Trackback : http://dev.heartsavior.net/archives/170/trackback/

우선 AJAX 개념이 필요하다면 아래 포스트들을 참조…

@ Head Rush Ajax / 동기 & 비동기 + AJAX 기본 흐름
@ ASP + AJAX Step 1 / Step 2 / Step 3

ASP 사이트에서 IIS 외의 웹 서버에서 AJAX 요청을 수행하려고 했지만, Cross Domain 정책에 막혀 실패했다.

구글링을 열심히 해 본 결과, 몇 가지 방법을 찾을 수 있었다. (방법들이 깔끔하게 요약된 포스트가 있어서 링크한다.)

@ Cross Domain Ajax: a Quick Summary

그 중에 Web Proxy 를 사용하기로 결정!
가장 쉬워보였고, 무엇보다 야후 개발자 네트워크에 설명되어 있어서…;;
야후 OpenAPI 를 이런 식으로 사용하길 권장하는 것이니 괜찮은 방법일 것으로 보인다.

@ Use a Web Proxy for Cross-Domain XMLHttpRequest Calls - Yahoo! Developer Network

위의 포스트에는 PHP 로 proxy 를 만들어서 쓰고 있는데, ASP 사이트이기 때문에 ASP 로 proxy 를 만들어 보려 했지만 결국 실력이 딸려 프로그래밍 갤러리에 약간의 도움을 받고(도움 요청글) 코드를 정리해서 완성했다.
(JSP로는 껌일 것 같은데 ASP는 전혀 모르겠다… ‘어플 프로그래머니까…’ 라는 핑계를…-_-;; )

먼저 내가 갖고 있었던, Cross-Domain의 문제를 가지고 있던 코드를 내부 페이지를 호출하도록 변경…

<html>
	<head>
		<title>AJAX TEST - FROM SimpleHttpServer</title>
 
		<script>
			function newXMLHttpRequest() {
				var xmlreq = false;
 
				// IE가 아닌 브라우저
				if(window.XMLHttpRequest) {
					xmlreq = new XMLHttpRequest();
 
				} 
				// IE
				else if(window.ActiveXObject) {
					try {
						// 최근 IE
						xmlreq = new ActiveXObject("Msxml2.XMLHTTP");
					} catch(e1) {
						try {
							// 예전 IE
							xmlreq = new ActiveXObject("Microsoft.XMLHTTP");
 
						} catch(e2) {
							// ALL FAILED !!
						}
					}
				}
 
				return xmlreq;
			}
 
			function getNewID() {
				var req = newXMLHttpRequest();
 
				// CALLBACK 메소드로 getReadyStateHandler를 등록
				var handlerFunction = getReadyStateHandler(req, showNewID);
				req.onreadystatechange = handlerFunction;
 
				// 첫번째 파라미터 - 방식(GET or POST)
				// 두번째 파라미터 - 주소
				// 세 번째 파라미터 - 비동기 여부(true가 비동기, false는 동기)
				req.open("GET","veoh.asp",true);
 
				// POST 이면 헤더도 바꿈
				/*
				req.setRequestHeader("Content-type", 
					"application/x-www-form-urlencoded");
				*/
 
				// 쿼리 스트링이 있을 경우 파라미터로 작성
				req.send(null);
 
			}
 
			function getReadyStateHandler(req, responseJSONHandler) {
				return function() {
					// AJAX에서 데이터를 완전히 얻어온 상태
					if(req.readyState == 4) {
						// 웹 서버에서 코드 200(성공) 을 리턴하였음
						if(req.status == 200) {
							// TEXT(JSON) DATA 가 req.responseText에 들어 있음
 
							// responseJSONHandler 파라미터로 넘어온 함수를 호출
							responseJSONHandler(req.responseText);
 
						} else {
							alert("HTTP error: " + req.status);
						}
					}
				}
			}
 
			// 실제 처리가 이루어지는 함수
			function showNewID(idJSON) {
				// JSON 문자열이 비었으면 에러
				if( idJSON == null ) {
					alert("idJSON is null!!");
					return;
				}
 
				alert(idJSON);
 
				// 일반 문자열에서 JSON으로 변환
				var jsonObject = eval('(' + idJSON + ')');
 
				// error 프로퍼티를 얻음
				var error = jsonObject.error;
 
				if( error == null ) {
					alert("JSON Parse Failed!!");
					return;
 
				} 
				// 성공할 경우 에러 코드 0, 실패할 경우  > 0을 넣어놓도록 되어 있음
				else if( error > 0 ) {
					alert("ERROR Returned!! Error Code : " + error);
					return;
				}
 
				// ID 프로퍼티를 얻음
				var id = jsonObject.ID;
 
				if( id == null ) {
					alert("JSON Parse Failed!!");
					return;
				} else {
					// 얻어온 ID값을 출력
					alert("ID Received!! ID : " + id);
				}
			}
		</script>
 
	</head>
 
	<body>
	<button onclick="getNewID()">새 아이디 얻기</button>
	</body>
</html>

AJAX로 내부 사이트의 proxy 페이지를 호출하며, proxy 페이지로 veoh.asp 를 사용한다.
veoh.asp 에서 외부 사이트의 내용을 넘겨주기만 하면 된다.
Cross-Domain 을 위한 ASP Proxy 페이지(veoh.asp) 는 아래와 같다.

< % @LANGUAGE="JSCRIPT" CODEPAGE="65001" %>
< %
	// Custom Functions
	function $_GET(values) {
		return Request.QueryString(values)!="undefined"?String(Request.QueryString(values)):null;
	}
 
	function echo(values) {
		Response.Write(values);
	}
 
	// Define Timeout Limit
	Server.ScriptTimeout = 10;
 
	Object.prototype.toParam = function(){
		var querystring = [];
		for (var inc in this) {
			if(!this.hasOwnProperty(inc)) continue;
			if (this[inc]!=null) {
				querystring.push(inc + "=" + Server.URLEncode(String(this[inc])));
			} else {
				querystring.push(inc + "=");
			}
		}
 
		return querystring.join("&");
	}
 
	var xmlHTTP = Server.CreateObject("MSXML2.ServerXMLHTTP");
 
	// 원래 AJAX 요청을 수행하려던 페이지를 호출한다
	xmlHTTP.open("GET", "http://www.example.com/idrequest", false); //, false, false);
 
	xmlHTTP.setRequestHeader("Content-type", "text/xml");
	xmlHTTP.setRequestHeader("Cache-control","no-cache");
 
	xmlHTTP.send();
 
	Response.Write(xmlHTTP.responseText);
 
	xmlHTTP = null;
%>

이렇게 하면 잘 된다. 흐흐… 문제는, 디버깅이 엄청 어려울 것으로 예상된다는거… 서버를 꺼놓고 테스트해보니까 404가 아닌 500 이 리턴됐고, 더 중요한 것은 exception catch 가 안된다 -_-;;

ps. 프로토타입(prototype.js) 으로 Cross Domain 을 해결하는 포스트가 있긴 한데 테스트는 못해봤음.

@ [PrototypeJS] Cross Domain상의 Ajax 호출


Aug 04 2008

VC++ 부동소수점 계산의 정확도를 높이는 방법

분류: Tip.Tech 태그: ,, , , Heart @ 10:48 오전

Trackback : http://dev.heartsavior.net/archives/164/trackback/

프로그래밍 갤러리에서 놀고 있었는데(…) 흥미로운 떡밥 하나가 올라왔다.
나도 모르게 덥썩 물어버렸다(…)

문제의 코드는 이것

#include <stdio .h>
 
int main(void)
{
float radius;
float area;
 
printf("원의 반지름 입력 : ");
scanf("%f", &radius);
 
area = radius*radius*3.1415;
 
printf("원의 넓이 : %f \n", area);
 
return 0;
}
</stdio>

글쓴이 말로는, VC++ 6 과 VS.net 2005 가 계산 결과가 다르게 나온다는 것이었다.

동강꺼랑 코드는 똑같애 12.0 입력했을 경우

내가 나온 값(VS.net 2005)은 452.376007
동강 나온 값(VC++6)은 452.376000

비슷한 문제를 GpgStudy 에서 찾을 수 있었다.
해결 방법 외에도 정확한 설명이 나와 있어서 기반 지식까지 쌓을 수 있었다.(물론 MSDN에 있는 내용… 이라지만 영어보다는 한글 설명이…^^;; 그리고 좀 덜 딱딱한 문체이기도 하고…)

@ assert의 버그?

답만 정리하자면, VC++ 6는 컴파일 옵티마이징 옵션중에 /Op (Improve Float Consistency)를 켜면 되고, VS 2008 은 기본이 /fp:precise (/Op를 대체) 로 되어 있어서 신경쓰지 않아도 된다.

이렇게 하면 위의 코드 실행 결과 VC++ 6 도 452.376007 이 나오게 된다.

자세한 것은 MSDN 자료를 참조하자.
vc++ 6 : http://msdn.microsoft.com/en-us/library/aa984742(VS.71).aspx
VS.net 2005~ : http://msdn.microsoft.com/ko-kr/library/e7s85ffb(VS.80).aspx

ps. 코드 하일라이트가 c/c++ include 태그 부분은 깔끔하지가 못한듯… 내가 잘못 쓴 건가…-_-;;


« 앞 쪽