블로그 이미지
포도알77
IT 방랑기

calendar

      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  

Notice

2019.04.03 22:06 프로그래밍/Javascript

1. HTML에서 Javascript만으로 IP 주소 얻기

HTML에서 IP주소를 확인하기 위한 방법으로 대부분 사람들이 Java script를 이용하려고 한다. 단도직입적으로 HTML내에서 Javascript만으로 IP 주소를 얻을 수 없다.

2.  IP address를 구하는 방법

서버는 사용자의 요청(Request)을 받을 때 TCP 또는 UDP 헤더를 보고 IP 주소를 알 수 있다.  즉, IP 주소를 얻기 위해서는 서버단에서 처리를하여 값을 되돌려 주어야 한다.

따라서 할 수 있는 방법으로 1. 서버를 구현한다. 2. API를 사용한다. 두개로 좁힐 수 있다.

(1) 서버를 구현하는 방법

 많은 사람들이 사용하는 Node.js나 php를 이용한다면, 많은 소스코드가 인터넷 상에 존재한다.  애초에 이런 방법을 찾기위해서 이 페이지를 찾은 것은 아닐 것이다.

(2) API 이용하기

 정말 간단하다. HTML에 아래의 스크립트를 추가하자. 그리고 Javascript에서 ip 변수를 이용하면 된다.

<script type="text/javascript" src="https://jsonip.com"></script>

그 이유는 서버가 클라이언트의 IP주소를 추출해서 변수에 하드코딩한 다음 스크립트로 반환한다. 이해가 안된다면 아래의 링크를 클릭해보자.

https://jsonip.com

posted by 궁금한 포도알77
2019.04.03 22:02 프로그래밍/Javascript

IP 주소를 이용하여, Geolocation 정보를 얻을 수 있다. 여기서 Geolocation은 위도경도 (Latitude, Longitude)를 뜻한다. 여기서 얻어지는 위도와 경도값은 굉장히 부정확하다. 그 이유는 ISP(인터넷 공급자)가 제공한 데이터를 이용하기 때문이다. 따라서 현재 위치는 서울이지만 조회 결과가 경기도로 나타날 수도 있다. 이

1. IP 주소 얻기

 현재 자신의 위치 정보를 얻는 방법은 [JS] HTML에서 JS를 이용하여 IP 주소 얻기를 참조하자.

2. Geolocation API 설명

 여기서 사용할 API는 ip-api.com가 제공한다. 이 사이트는 별도의 회원가입이나, 키발급 없이 바로 조회를 할 수 있다. 다만 분당 150회의 제한이 있으니 확인하기 바란다. 또한 영리의 목적으로 사용할 수 없다.

 우리가 위치 정보를 얻기 위해서 전달해야하는 정보는

http://ip-api.com/json/123.123.123.123?callback=yourfunction

 ip는 당연히 전달되어야 하고, callback은 선택사항인데, ip-api의 서버가 response할 때, client 스크립트 내의 함수를 호출해준다.

 즉, 조회후 데이터를 출력하는 함수가 printDataOnThePage()라면, printDataOnThePage를 입력하면 된다.

3. IP를 이용하여, Geolocation 정보 얻기

 IP를 이용하여, Geolocation을 얻기위해서는 동기(synchronous)방식으로 전달해도 되지만, 대부분 비동기(asynchronous)를 이용할 것이다.

전체적인 과정을 나타내면,

 (1) IP 주소를 얻는다.

 (2) AJAX를 통하여, ip-api 서버에 비동기 통신으로 Geolocation을 요청한다.

 (3) 결과를 제공받아 화면에 출력한다.

아래의 예제를 보자.

[코드]

<div style="padding-left: 60px;">
  ip : <input id="your-ip-addr" type="text" />
  Geo : <input id="your-geo" type="text" />
  <script type="text/javascript">
    function loadScript(url, callback){
      var script = document.createElement("script")
      script.type = "text/javascript";

      if (script.readyState){  //IE
        script.onreadystatechange = function(){
          if (script.readyState == "loaded" ||
                script.readyState == "complete"){
               script.onreadystatechange = null;  
               callback();
          }
        };
      }else {  //Others
         script.onload = function(){
            callback();
         };
      }
      script.src = url;
      document.getElementsByTagName("head")[0].appendChild(script);
    }
    loadScript("https://jsonip.com/?callback=ip", function(){
      var geoData, ipData = ip;
      document.getElementById("your-ip-addr").value=ipData;
      document.getElementById("your-geo").value="Wait..";
    
      var xhttp = new XMLHttpRequest();
      xhttp.onreadystatechange = function() {
        if (this.readyState == 4 && this.status == 200) {
          geoData = JSON.parse(this.responseText);
          printDataOnThePage();
        }
       };
      xhttp.open("GET", 
                 "http://ip-api.com/json/"+ipData,
                 true);
      xhttp.send();
      function printDataOnThePage(){
        document.getElementById("your-geo").value=
          geoData.lat+' '+geoData.lon+' '+geoData.city;
      }    
    });

  </script>
</div>

AJAX를 잘 모른다면, W3School AJAX를 먼저 보자. 우선 ip주소 스크립트를 로딩하기 전에 실행될 수 있으므로, 스크립트를 로딩후에 함수를 동작하게 하는 "loadScript"부분을 추가하였다. 이부분이 잘 이해가 되지않는다면, 전체를 긁어다가 쓰면된다.  그건 각자가 알아서 해결하면될 문제이고, 간단히 ip를 받아서 Ajax를 통해 ip-api서버로 요청을 보내고 그 결과를 input 태그에 담는다.

모르겠다면 댓글로

posted by 궁금한 포도알77
2019.03.28 08:34 프로그래밍/Javascript

1. HTML 주석 지우기

 자바 스크립트로 HTML 엘리먼트의 값을 받아 올 때, HTML 주석이 같이 들어있는 경우가 있다. 이때 HTML의 주석을  정규식을 이용하여 효과적으로 제거한다.

function rmComment(str){
  return Number(str.replace(/(<([^>]+)>)/ig, "").replace(/,/ig, ""));
}

 

2. 숫자 comma 넣기

 자바 스크립트로 숫자를 입력할 때,  1000단위에서 comma를 넣어주는 경우를 정규식을 이용하여 수행한다.

function commify(n) {
  var reg = /(^[+-]?\d+)(\d{3})/;
  n += '';                         
  while (reg.test(n))
    n = n.replace(reg, '$1' + ',' + '$2');
  return n;
}

 

posted by 궁금한 포도알77
2019.03.28 08:30 프로그래밍/Javascript

CORS 이슈 Access-Control-Allow-Origin 문제 해결하기

 

 

 

 CORS 크로스 도메인 이슈

 AJAX를 이용하여, 다른 API의 데이터를 가져오려고 할 때, 갑자기 나타나는 에러이다. 정확한 원인은 알아보지 않아 잘 모르겠지만, 아무튼 같은 URL에서만 호출을 하도록 강제하는 정책이다. 아마도 브라우저 단에서 처리하는 것 같다.

 

 

 

해결 방법

 아무튼 그런건 모르겠고, 해결방법은 여러가지가 있다.

  1) 브라우저의 옵션으로 처리하기

  2) 크롬 플러그인을 설치하기

  3) 트릭

 

 

 사실 1~2번 방법이 의미가 없는게, 웹 서버 사용자에게 ActiveX처럼 설치하라고 강요할 수 없기 때문. 아무튼 해결 방법은 이렇게 하면 된다.

<script>
   $.ajax({
      url: "https://URL/",
      dataType: 'jsonp',
      success: function(data) {
        console.log('success - ', data);
      },
      error: function(xhr) {
        console.log('failure - ', xhr);
      }
    });
</script>

 

!!! JQUERY는 필수, 아직 시간이 없어서 JS만으로 처리하는 방법을 안찾아봄.

방법은 CSS나 JS와 같은 스크립트 로딩시에는 아무런 문제가 되지 않는 것을 이용하여, 브라우저를 속이는 것이다.

JSONP 타입을 이용하는데, 관련된 사항은 알아서 찾아보자.

posted by 궁금한 포도알77
2019.03.11 08:17 프로그래밍/Javascript


 Javascript에서 Associative array는 C++의 map이나 Python의 dictionary와 같은 데이터 타입이다.


 Javascript의 Array의 경우  손쉽게 prototype에 정의된 sort를 사용할 수  있으나, Associative array의 경우 사용자 정의 데이터 타입에 가깝기 때문에 Compare 함수를 만들어 줘야한다. 



 Associative array가 key : value 타입으로 정의되어 있다면, 아래와 같이 만들면 된다.


function aasort(arr){
    var tuples = [];
    for (var key in arr) tuples.push([key, arr[key]]);
    tuples.sort(function(a, b) {
        a = a[1];
        b = b[1];
        return a < b ? -1 : (a > b ? 1 : 0);
    });
	return tuples;
}
 

 만약 그외의 형태라면, tuples.push당시에 해당 값을 넣어주면 된다. 또한 리턴할 필요가없다면, 그냥 함수를 만들지말고 for loop을 수행하면서 처리해도 무방하다.



posted by 궁금한 포도알77
2019.03.10 15:52 프로그래밍/서버
 대부분의 웹 서비스 프레임워크에서 세션을 관리하는 기능을 제공한다.  

 이런 세션 기능들은 1번 로그인을 하면, 브라우저내의 어떤 탭에서도 로그인이 유지된다. 하지만 일부 프로젝트는 반드시 1계정 1세션 유지가 정책이 되어야 하는 경우도 있다.  



 [세션의 정의와 세션 관리 기능이 동작하는 방법] 

 어떤 프레임워크를 사용하든지, 세션은 서버 기준의 1개의 일시적인 연결이다. 즉, 어떤 클라이언트가 접근하였을때 세션 ID를 만들고, 로그인시 클라이언트의 정보를 해당 세션 ID(Key)에 대한 값(Value)로 저장한다.


 그리고 마지막으로 클라이언트 브라우저에게 해당 세션 ID(세션 ID, 세션 Key를 혼용하겠음)를  전달해주면서, 해당 세션키를 이후 모든 연결에 전달하라고 요구한다. 이 경우 브라우저는 이 세션키를 쿠키에 저장하게 된다. (따라서 모든 탭에서 접근이 가능하다.==로그인 상태가 유지되어있다.)   


 따라서 1 계정 1 세션을 위해서는 세션값이 아닌 새로운 임의문자열을 로그인시마다 생성하여, 클라이언트에게 전달해야한다. 이 임의문자열을 UID라고 정의하고 계속 글을 이어간다.




 방법1) 

 우선 가장 간단한 방법은 계정 ID를 Key로하여, Value에 세션 ID와 UID을 매칭하여 저장한다음, 동일하게 클라이언트 브라우저에게 전달한다. 그리고 해당 계정이 다른 브라우저에서 로그인하였을때, 이 값(세션과 UID)과 비교하여 현재 계정이 사용중인 세션을 저장한다. 

 이렇게 세션키를 저장하면 서버는 항상 새로운 세션키 값을 저장할 수 있고, UID를 바탕으로 사용자는 항상 마지막 로그인이 발생한 세션에서만 로그인이 유지된다.  


 하지만 방법1은 틀렸다. 따라서 1 계정 1로그인 정책을 설정하기 위해서는 UID를 브라우저에 저장하는 방법(Set cookie)이 아닌, 한 탭에서만 관리되는 곳에 저장해야한다. (쿠키는 브라우저의 모든 탭에서 공유된다. 세션 스토리지, 로컬 스토리지도 마찬가지다)  


 그렇다면 탭마다 관리되는 메모리 영역은 무엇일까? 바로 HTML과 JS영역이다. 즉 서버와 통신할때, 이제부터는 항상 HTML 또는 JS 영역에서 UID 값을 읽고 이를 포함하여 전달해야한다.




 
 방법2) 

 Sync 방식에서는 페이지가 전환되어 버리므로, 이전 HTML, JS영역이 메모리상에서 제거된다. 따라서 서버에 Query 스트링으로 전달하면서, 서버가 이를 다시 릴레이해줘야한다.

 [ex] 
       (1) GET /index?uid=abcd -----> 
       (2) 서버 uid 확인 -----> 
       (3) index내의 html 태그에 uid를 포함하여 클라이언트에게 전달. 

 Async 방식에서는 페이지 전환이 없으므로, 지속적으로 html 또는 js영역에서 이를 관리하면된다.  



(요약)

 (1) 1 계정 1 세션은 기본적인 프레임워크 세션 관리 기능만으로는 불가능하다.
 (2) 브라우저의 탭은 동일한 세션 아이디를 가지므로, 동일 계정이 로그인하는 경우 이를 공유한다. 
 (3) 각 세션을 서버가 구분하기 위해서는 고유 ID를 부여하여야 한다.
 (4) 각 로그인별 고유 ID를 발급하고, 이를 클라이언트에게 전달한 다음 이 값으로 가장 최근 세션을 찾는다.
 (5) 이를 쿠키, 세션스토리지, 로컬스토리지에 저장하면, 이 또한 공유하므로 의미가 없다.
 (6) 탭별 고유 메모리 영역인 HTML, JS에 저장하자.  


 추신) Ajax의 경우에는 sendBefore, complete 이벤트 리스너를 통하여 UID를 전달할 수 있다.
$.ajaxSetup({
  beforeSend: function (xhr){
     // 모든 AJAX를 보내기전에 헤더에 UID를 포함한다.
     xhr.setRequestHeader('uid', $('.uid').text());
  },
  complete: function(xhr){
  }
});
   


posted by 궁금한 포도알77
2019.03.10 15:46 프로그래밍/Javascript
 jQuery에서 동일한 DOM의 반복적인 selector를 사용을 방지하기 위해서나, K-V 형식으로 데이터를 저장할때 Object를 많이 사용한다. 

 이런 Object안에서 전체 Key를 찾아 순회할 때, Object.keys(obj)형식을 많이 사용한다. 

 특히, Object.keys(obj).forEach(function(k,v){})를 이용하여 Loop 문까지 한번에 처리하는 경우가 많은데, 여기서 Callback을 사용하는 경우 callback 호출후에도 루프가 Break되지 않는 문제가 생긴다.  


var obj = { 'abc':1 , 'bcd':2'};
function run(obj, callback){
	Object.keys(obj).forEach(function(k,v){
		if(k == 'abc') return callback(v);
		console.log(key);
	});
}
function callback(value){
	console.log('DONE', value);
}

run(obj, callback);


// LOG --> DONE abc
// LOG --> bcd


  Object.keys의 forEach의 경우 콜백 함수로 익명 함수 function(k,v)를 받게 되는데, 이 경우에 루프를 돌면 return을 하면 다음 obj의 key를 찾아 오는 동작으로 연결된다. 


 즉, return이 break 역할이 아닌 continue 역할이다. 


 이런 코드를 짜는 경우 지저분해지더라도 Object.keys(obj)를 배열로 받고, for loop를 수행하는게 좋다.



posted by 궁금한 포도알77
prev 1 next