제2의 비엔지니어 인생관을 꿈꾸며

Posted
Filed under jQuery
IFRAME 요소(HTML5 지원)

iframe 요소는 인라인 프레임(Inline FRAME)을 표시한다.
- 인라인 프레임은 문서 내에 다른 문서를 넣기 위한 기술이다
- HTML5로 바뀌면서 frame 요소는 사라졌지만 iframe 요소는 남았다.
- HTML5에 새로이 추가된 속성 및 사라진 속성들이 존재한다.

src 속성
src 속성은 인라인 프레임으로 제공할 소스(source)를 지정한다.


sandbox 속성
HTML5에서 새로이 추가된 속성으로서, 보호구역으로 지정하여 해당 프레임에 삽입되는 페이지에 다음과 같은 제한을 둘 수 있다.

<iframe src="test.html" ></iframe>
*  실제 존재하지 않는 도메인(오리진)에 속한 것으로 간주함. 따라서 자신이 소속된 도메인과도(allow-scripts에 의해 실행이 가능
    해져도)  통신할 수 없음
* 플러그인(ActiveX, 플래시등) 실행금지
* Javascript 사용금지
* 폼 요소에 의한 페이지 호출금지
* 부모 문서를 대체하는 브라우징이 불가능

위의 제한이 너무 엄격하여 iframe 안의 페이지가 동작하지 않을때는 sandbox 속성에 다음과 같은 값을 지정하여 샌드박스 제한을 완화할 수 있다.

| allow-same-origin
원칙적으로 다른 도메인의 문서가 인라인 프레임을 통해 제공될 때는 부모 문서(parent document)에 접근할 수 없다. 이럴 때는 allow-same-orign 속성값을 이용하면 다른 도메인의 문서를 같은 도메인의 문서로 간주하여 부모 문서에 접근할 수 있게 된다(서버와의 통신, 스토리지 이용등)
<iframe src="http://www.example.com/test.html" sandbox="allow-same-origin"></iframe>






| allow-top-navigation
원칙적으로 다른 도메인의 문서가 인라인 프레임을 통해 제공될 때는 부모 문서를 대체하는 브라우징은 불가능하다. 이럴 때는 allow-top-navigation 속성값을 이용하면 인라인 프레임에 있는 링크를 클릭했을 때 부모 문서가 사라지고 외부 문서가 나타나게 하거나 새창을 열어 새로운 브라우징할 수 있도록 처리할 수 있다.
<iframe src="http://www.example.com/test.html" sandbox="allow-top-navigation"></iframe>



| allow-form

원칙적으로 다른 도메인의 문서가 인라인 프레임을 통해 제공될 때는 폼 데이터를 다른 곳으로 보낼 수 없다. 이럴 때는 allow-forms 속성값을 이용하면 인라인 프레임에서 폼 데이터를 다른 곳으로 보낼 수 있다.
<iframe src="http://www.example.com/test.html" sandbox="allow-form"></iframe> 


| allow-scripts
원칙적으로 다른 도메인의 문서가 인라인 프레임을 통해 제공될 때는 스크립트 실행은 허용되지 않는다. 이럴 때는 allow-scripts 속성값을 이용하면 인라인 프레임에서 스크립트를 실행시킬 수 있다. 단 팝업창은 허용되지 않는다. 스크립트는 여러 가지 보안 상의 문제를 야기시킬 수 있기 때문에 신뢰할 수 있는 문서일 경우에만 허용해야 한다.
<iframe src="http://www.example.com/test.html" sandbox="allow-scripts"></iframe> 


출처  : http://webdir.tistory.com/312?category=607030

2018/02/08 15:23 2018/02/08 15:23
Posted
Filed under jQuery
| 클라이언트 
var formData = new FormData($("#frm")[0]);

$.ajax(
              {

                        url : "krMy_ExcelRead.asp" ,
                        type : "POST" ,
                        async : false ,
                        cache : false,
                        data : formData,
                        processData: false  // 데이터 문자열을 자동으로 쿼리스트링으로 변환되는것을 false
                        contentType: "application/x-www-form-urlencoded; charset=UTF-8",
                        dataType : "text",
                        timeout : 10000,
        
                        complete: function(jqXHR)
                        {

                                 alert("complete") 
                        },

                        success: function(jqXHR)  
                        {

                                alert("upload success"); 
                        } ,

                        error : function(jqXHR)   
                        {
                                alert("upload Error");
                        }
        

        }
);


| 서버 단 소스(classic ASP)
 서버단은 기존에 form 넘겨 받드시 그대로 작성하면된다. ajax라도 다를께 없다. (서버 코드는 본인의 상황에 맞게 알아서 코딩)
<%
        Response.Expires = 0
        Response.Buffer = True
        Server.ScriptTimeOut = 25 * 60 * 60

        filePath = Server.mapPath("../temp/") & "\"

        Set objFSO = CreateObject("Scripting.FileSystemObject") '파일시스템 개체 생성
        Set fForm = server.createobject("ABCUpload4.XForm")
        fForm.MaxUploadSize = 10240000 '최대업로드용량 '10메가(디폴트는 8메가)
        fForm.AbsolutePath = True
        fForm.Overwrite = true

        Set theField = fForm("file")(1)

        strFilePath = theField.RawFilePath '파일의 클라이언트 경로
        strFileName = Mid(strFilePath, InstrRev(strFilePath,"\") + 1) '경로명을 제외한 파일명 추출
        strStoreFileName = filePath & strFileName 

        theField.Save strStoreFileName

%>        
2018/02/01 19:13 2018/02/01 19:13
Posted
Filed under MSSQL
MSSQL 의 대용량 데이터 관리를 위한 파티셔 테이블 에 대해서  시나리오 별로 작성해 보았다.
우선 파티셔닝에 대해 왜 필요한지 어떤게 장점이고, 단점인지 뭔지, 뭐하는건지에 대한 내용은 설명되어있지 않다. 간략하게 설명 드리자면, 대용량 데이터 베이스 환경에서, 데이터가 관리되는, 최소규모의 테이블을 물리적 & 논리적 분할을 통해 I/O 및 기타 성능을 높이는데 목적이 있다. 자세한건 구글링을 통해 알아보도로 하고, 다음 포스팅에 다시한번 파티셔닝을 다룰때 이야기 하도록 하자

  테스트를 위한 시나리오 , SQL 풀 쿼리이다.(다운로드)


포스팅의 내용을 살펴보면,
# DB 생성 또는  기존 DB 에 그룹 추가 후 그룹별 파티셔닝하기 (Primary 1개 + 그룹 5개)
   >  쿼리 연습겸 , 3개는 Create DATABASE 로 나머지 2개는 Alter DataBase 로 처리
# 기본 DB 에 , 쿼리로 DB 에 파일 그룹 추가해 보기 (기존에 단일 그룹  > 그룹으로 추가하는 방법을 알수있음)
# 파티셔닝에 필요한  쿼리들을 알수있다. (Partition Function , Partion Scheme  , Create Table , Create Index )
# 파티셔닝  관리에 필요한 명령어 처리(SPLIT , MERGE , SWITCH)
| 자세한 내용은 상황 별로 설정하여 그때 그때 쿼리 및 이미지 주변에 설명에 두었으니, 참고하길 바랍니다.


DB 생성(그룹동시생성)  및 alter 명령어로 그룹추가
CREATE DATABASE partitionDB
ON
Primary  (Name = "partitionDB_PM" , FileName="D:\TEST_DATA\pDB_M.MDF"),  

FileGroup FG1 (name= "partitionDB_FG1" , FileName  ="D:\TEST_DATA\fDB_1.NDF") ,
FileGroup FG2 (name= "partitionDB_FG2" , FileName  ="D:\TEST_DATA\fDB_2.NDF") ,
FileGroup FG3 (name= "partitionDB_FG3" , FileName  ="D:\TEST_DATA\fDB_3.NDF") 


Alter DataBase [partitionDB] add FileGroup [FG4]
Alter DataBase [partitionDB] add File  (Name ="partitionDB_FG4", FileName = "D:\TEST_DATA\fDB_4.NDF") 
To FileGroup  [FG4]


Alter DataBase [partitionDB] add FileGroup [FG5]
Alter Database [partitionDB] add File (Name = "partitionDB_FG5", FileName = "D:\TEST_DATA\fDB_5.NDF") 
To FileGroup [FG5]


use partitionDB 


DBCC SHOWFILESTAT


파티션 함수생성
CREATE PARTITION FUNCTION [PF_For_Date_FG5] (datetime)
AS
RANGE LEFT FOR VALUES
(
            '2017-03-01 00:00:00' ,  -- 'RegDate 값' <= 2017-03-1 
            '2017-06-01 00:00:00' ,  -- 'RegDate 값' <= 2017-06-1 
            '2017-09-01 00:00:00' ,  -- 'RegDate 값' <= 2017-09-1
            '2017-12-01 00:00:00' ,  -- 'RegDate 값' <= 2017-12-1 
            '2018-03-01 00:00:00'    -- 'RegDate 값' <= 2018-03-1                      
  ) 

파티션 펑션  쿼리 확인
select * From sys.partition_functions
select * From sys.partition_range_values





파티션 스키마 생성
CREATE PARTITION SCHEME [PS_For_Date_FG5] 
AS 
PARTITION [PF_For_Date_FG5] To ([FG1], [FG2], [FG3], [FG4], [FG5])
*  스크립 생성하면 오류난다? 왜지? 그룹5개만들도 다 맞는데?
*   2018-03-1 <  이후 데이터가 들어갈곳이없다.
*  그래서 그룹생성시 파티셔닝할 그룹 + 1개(사실은 1개 이상) 그룹을 추가로 만들어야함


[FG6] 파일그룹 추가
ALTER DATABASE [partitionDB] add FileGroup [FG6]
ALTER DATABASE [partitionDB] add File (name = "partitionDB_FG6" , filename = "D:\TEST_DATA\fDB_6.NDF")

DBCC SHOWFILESTATS

| 오잉? 이상하다
| 방금만든 [partion_FG6] 이 Primary 와 같은 FileGroup 1 에 들어가있다 
| To FileGroup 옵션을 빼먹었다. --; 삭제하고다시하자

[FG6]  파일그룹을 만들고 & 물리적 파일을 [FG6] 그룹에 적재 
① [FG6]  파일그룹을 생성
Alter database [partitionDB] remove filegroup [FG6] -- 그룹  삭제
Alter database [partitionDB] remove file [partitionDB_FG6] -- 파일  삭제

ALTER DATABASE [partitionDB] add FileGroup [FG6]
ALTER DATABASE [partitionDB] add File (name = "partitionDB_FG6" , filename = "D:\TEST_DATA\fDB_6.NDF") To Filegroup [FG6]
 만약  그룹(TO Filegroup 그룹명) 으로 생성된 파일그룹 삭제시 ① FILE (*.NDF)를 삭제 후  ② FileGroup 을 순서대로
삭제되어야 한다. (논리적으로 [FG6] 안에 물리 파일인[partitionDB_FG6] 이 있기때문)

DBCC SHOWFILESTATS
 | FileGroup 7번을 정상적으로 할당 받았다



② 파티션 스키마에 [FG6]
CREATE PARTITION SCHEME [PS_For_Date_FG5] 
AS 
PARTITION [PF_For_Date_FG5] To ([FG1], [FG2], [FG3], [FG4], [FG5])


| 또 오류  왜 그러지?
| 방금 만든 [FG6] 를 추가해야한다.
| 기본 [FG1] ~ [FG5] 까지는 파티션 함수에서 지정한 조건에 맞는 데이터가 파티셔닝되고
| 그 외의 조건은 [FG6] 에 들어가도록,
| PARTITION SCHEME 생성시에는 PARTITION FUNCTION 지정한 그룹 갯수 + 1개 이상을 추가 해야 한다.



아래쿼리 정상처리
CREATE PARTITION SCHEME [PS_For_Date_FG5] 
AS 
PARTITION [PF_For_Date_FG5] To ([FG1], [FG2], [FG3], [FG4], [FG5] , [FG6])


테이블 생성 & 인덱스 생성시 파티셔닝 하기
Create table Tbl 
(
      idx int ,  
      RegDate datetime
)  ON PS_For_Date_FG5(regdate)
| 테이블에 인덱스 생성시 파티션용 스키마 적용 하여 테이블 파티셔닝 한다.



CREATE NONCLUSTERED INDEX IDX_DUMMY
ON Tbl (regDate)
ON PS_For_Date_FG5 (RegDate) 
| 위의 테이블 생성시 , 테이블에 인덱스 생성시 파티션용 스키마 적용 하여 테이블 파티셔닝 한다.
| 나는 일부러 넌클러스터 인덱스로 해보았다. 다음 포스팅에 파티션인덱스를 다룰때 3가지 "인덱스없이,넌클러스터,클러스터" 를 해보자


tbl에 더미 데이터 넣기
declare @i int
declare @d datetime
set @i = 1 
set @d = '2017-01-01'
BEGIN TRAN
WHILE @i <= 10000
Begin 
        set @i = @i + 1
        insert Tbl values (@i , dateadd(hh ,  @i , @d) )
End
COMMIT TRAN


분할된 파티션 정보를 그때 그때 눈으로 확인하기위해 아래 프로시져를 생성해두자
Create proc sp_partiton_view  -- drop proc sp_partiton_view
        @tbl varchar(50)
as
select 
        F.Name ,
        G.partition_number  , 
        G.Rows ,  
        E.value  
rom 
sys.destination_data_spaces A
        left outer join sys.indexes B on A.partition_scheme_id = B.data_space_id 
        left outer join sys.tables C  on B.object_id = C.object_id
        left outer join sys.partition_schemes D on B.data_space_id = D.data_space_id 
        left outer join sys.partition_range_values E on E.function_id = D.function_id and E.boundary_id = A.destination_id
        left outer join sys.filegroups F on F.data_space_id = A.data_space_id  
        left outer  join sys.partitions G on G.object_id = C.object_id and  G.index_id = B.index_id 
        
                                                        and G.partition_number = A.destination_id
where C.name = @tbl and B.name is not null order by partition_number asc



위에 만들어지 프로시져를 한번 써서, 파티션별로 들어간 데이터 갯수 눈으로 확인해보자
sp_partiton_view 'tbl'

기존 (파티셔닝기준) 데이터로  파티션 위치 확인
SELECT $PARTITION.[PF_FOR_DATE_FG5] ('2017-06-01') 
SELECT $PARTITION.[PF_FOR_DATE_FG5] ('2018-07-01') 
| '2017-06-01' 날짜로 PF_For_Date_FG5 파티션 평션 적용시켜 insert 하면  몇번째 Partition_number 로 들어갈까?
| '2018-07-01' 날짜로 PF_For_Date_FG5 파티션 평션 적용시켜 insert 하면  몇번째 Partition_number 로 들어갈까?
 결과는 아래와 같다.






파티션 SPLIT ①

" 새로운 파티션 추가 #1
시나리오 :  새로운 그룹 [FG7] 생성 후 2018-06-01 추가 "

추가전, 현재 상태를 먼저 확인해보자
sp_partiton_view 'tbl'

| 현재 파티셔닝된 상태 확인

새로 추가될 그룹 추가 생성
ALTER DataBase [partitionDB] add filegroup [FG7]
ALTER database [partitionDB]  add File (Name = "partitionDB_FG7", FileName = "D:\TEST_DATA\fDB_7.NDF") To FileGroup [FG7]

파티션 스키마에 추가 다음으로 파일그룹 FG7 지정
ALTER PARTITION SCHEME PS_For_Date_FG5 Next USED [FG7]
ALTER PARTITION FUNCTION PF_For_Date_FG5()  SPLIT RANGE('2018-06-01 00:00:00') -- 함수명뒤에 '()' 없으며 구문 오류남
| 파티션 평션에 부합되지않은 [FG6] 에 있던 데이터들 중 추가된 파티션 정보에 부합되는 정보가 있으면
| 그쪽 그룹으로 데이터가 이동하는 작업이(삭제/입력 I/O발생 나머지는 그대로 잔류




추가된 Partition_number 6 : [FG7] 확인
sp_partiton_view 'tbl'
| 새로운 파티션 스키마 정보가 삽입되면서 partition_no:6 에서 -> partition_no : 7 로 밀림

제대로 분할되었는지 테스트 INSERT
insert tbl values(10001 , '2018-04-01') -- 2번  실행
insert tbl values(10001 , '2018-06-01') -- 3번 실행



sp_partiton_view 'tbl'




파티션 SPLIT ②

 새로운 파티션 추가 #2
시나리오 : 기존에 파티션정보에 이미 '2017-01-01' 이 사용중인 [FG1] 를 다른 조건으로 파티셔닝하기
[FG6] 은 기존에 위의 조건 외의 데이터가들어가는 그룹이었다  "
 ALTER PARTITION SCHEME PS_For_Date_FG5 Next USED [FG1]
    ALTER PARTITION FUNCTION PF_For_Date_FG5()  SPLIT RANGE('2018-09-01 00:00:00') 
추가된 Partition_number 6 : [FG7] 확인
sp_partiton_view 'tbl'


insert tbl values(10001 , '2018-07-01') -- 2번 실행
insert tbl values(10001 , '2018-08-01') -- 4번 실행
sp_partiton_view 'tbl'




파티션 SPLIT ③

 새로운 파티션 추가 #3
시나리오 : 새로운 그룹 [FG8] 생성 후 2018-06-01 추가 "
ALTER DataBase [partitionDB] add filegroup [FG8]
ALTER database [partitionDB]  add File (Name = "partitionDB_FG8", FileName = "D:\TEST_DATA\fDB_8.NDF") To FileGroup [FG8]


스키마에 [FG8] 추가하고 범위 지정
ALTER PARTITION SCHEME PS_For_Date_FG5 Next USED [FG8]
ALTER PARTITION FUNCTION PF_For_Date_FG5()  SPLIT RANGE('2018-12-01 00:00:00')
sp_partiton_view 'tbl'

| 기본 그룹의 partitinu_number 가 다시 도 밀려나는걸 볼 수 있다.

insert tbl values(10001 , '2018-11-01') -- 4번 실행
insert tbl values(10001 , '2018-12-01') -- 5번 실행

sp_partiton_view 'tbl'




 파티션 MERGE
> 기존에 분할된 파티션 영역을 합친다.
> '2018-12-01 00:00:00.000' 조건을 가지고 있는 Partition_Num 8 (FG8)을 Merge(합침)
> 합쳤을때 데이터가 파티션 함수 조건에 맞는 데이터가 아니라면 기본 그룹에 INSERT 됨

 ALTER PARTITION FUNCTION PF_For_Date_FG5() MERGE RANGE ('2018-12-01 00:00:00.000')

sp_partiton_view 'tbl'


| Merge 한  파티션에 있던 데이터들('2018-12-01') 이  파티셔닝된 조건에 맞는 파티션이 없으므로,  
기본 파티션된 그룹 partition_number 8 인 [FG6] 에 들어감.
 

중간에 있는 2018-06-01 파티션을 Merge 해보자
ALTER PARTITION FUNCTION PF_For_Date_FG5() MERGE RANGE ('2018-06-01 00:00:00.000')
sp_partiton_view 'tbl'

| Merge 한  파티션에 있던 데이터들('2018-06-01') 이  파티셔닝된 조건에 맞는 파티션이 partition_number 6번에
있으므로, partition_number 6 인 [FG1] 에 들어감.
 



파티션 SWITCH 
> SWITCH 작업 전에 두 테이블이 존재해야 합니다..
> 파티션 SWITCH 조건을 MSDN 을 통해 찾아보면
   ①받는 파티션이 존재하되 비어 있어야 합니다.
   ②분할되지 않은 받는 테이블이 존재하되 비어 있어야 합니다
   ③파티션은 동일한 열에 있어야 합니다. 
   ④원본 및 대상 테이블은 동일한 파일 그룹을 공유해야 합니다. 


파티셔닝된 Tbl 의 구조를 확인하고  같은구조의 tbl_tmp 를 만든다.
(위의 조건을 무시하고 primary 그룹에 그냥 만들어보자)
select * from tbl
select * into tbl_tmp from tbl where idx = -1 -- 스키마만 복사
SWITCH 시작
 ALTER TABLE tbl SWITCH PARTITION 5 TO TBL_TMP


| 오류! SWITCH 하기위해 PARTITION_NUM 6 번 데이터를 tbl_tmp 로 switching 시도했으나 안됨
| ④ 원본 및 대상 테이블은 동일한 파일 그룹을 공유해야 합니다. 항목 위반
< 각각의 테이블 파티션 정보 & 테이블 정보 보기 >
원본 tbl  파티션된 정보보기
SELECT * FROM SYS.PARTITIONS where object_id = object_id('tbl')  
order by index_id  , partition_number 


타켓 tbl_tmp  파티션된 정보보기
SELECT * FROM SYS.PARTITIONS where object_id = object_id('tbl_tmp')  
order by index_id  , partition_number 






 각 테이블이 어떤구조로 있는지 눈으로 확인 

select 'tbl' , * from sys.indexes where object_id = object_id('tbl') 
select 'tbl_tmp' , * from sys.indexes where object_id = object_id('tbl_tmp')




select * From sys.data_spaces where data_space_id = 65601 -- PRIMARY 에 속해있다.
select * From sys.data_spaces where data_space_id = 1 -- 파티션 그룹(PARTITION_SCHEME)에 속해있다


drop table tbl_tmp -- drop 하고 다시생성

스키마 참조하여 만들되,  이번엔 일부러 컬럼명만 다르게 해보았다.
 create table tbl_tmp (idx2 int , regdate2 datetime) on [PS_For_Date_FG5](regdate2)

> 다시 스위칭 시킨다. PARTITION_NUM 5 번에 있는거 4145개 데이터 SWITCH
> 각각의 원본의 PARTITION NUM 과 타깃(TBL_TMP) 파티션 번호를 틀리게 줘봤다

ALTER TABLE tbl SWITCH PARTITION 5 TO TBL_TMP PARTITION 5

| 오류 발생 컬럼명 다르다고 오류



스키마 참조하여 만들되,  이번에는 컬럼명도 같게 MSDN 시키는대로
drop table tbl_tmp
create table tbl_tmp (idx int , regdate datetime) on [PS_For_Date_FG5](regdate)
파티션 번호 다르게 해볼까?  오류 발생
ALTER TABLE tbl SWITCH PARTITION 5 TO TBL_TMP PARTITION 1
> 오류 : 그룹이 다르다고 오류를 뱉길래 조건이 다른 1/6번 그룹은 같은 FG1 얘는될까?

ALTER TABLE tbl SWITCH PARTITION 1 TO TBL_TMP PARTITION 6
> 오류 : 정의한 범위가 테이블 'partitionDB.dbo.TBL_TMP'의 파티션 6에서 정의한 범위에 포함되지 않습니다.
원하는대로 같은 파티션에 SWICH 처리 → [성공]
ALTER TABLE tbl SWITCH PARTITION 5 TO TBL_TMP PARTITION 5


확인 [FG5] 에 있는 데이터들이 모두 TBL_TMP 로 INSERT 되었다.
sp_partiton_view 'tbl'


테이블을 확인해보자
PARTITION_NUMBER 5 에 있던 데이터 1985개 그대로 TBL_TMP 에 들어가있다.
select count(*) From TBL_TMP
| 정확히 이야기하자면 TBL_TMP 테이블의 PARTITION_NUM 5 에 FG5 에 들어가있다.
| PARTITION_NUMBER 5 에 그대로 들어가있다.




SELECT * FROM SYS.PARTITIONS
Where object_id = object_id('tbl_tmp')  Order by index_id  , partition_number 



SELECT * FROM SYS.PARTITIONS 
Where object_id = object_id('tbl')  Order by index_id  , partition_number 



| index_id 가 왜  2개지?  나중에  인덱스에 대해서 포스팅할대 설명하기로하자 급하신분들은 구글링 하시길



PARTITION_NUMBER 5를  삭제하자(삭제는아니고 사실 Merge 이다)
sp_partiton_view 'tbl' -- 삭제 전확인


PARTITION_NUMBER 5를  삭제하자 (Merge)
 ALTER PARTITION FUNCTION PF_For_Date_FG5() MERGE RANGE ('2018-03-01 00:00:00.000')

sp_partiton_view 'tbl' -- 삭제 후 확인 (사실 삭제라기 보다 합쳐젔다)


아차! 테스트하다가 파티션 범위 밖의 데이터를 입력해보는것을 해보지 못하였다.

sp_partiton_view 'tbl'


파티셔닝 조건인 value 에 포함이 안되는 값(날짜) insert
 insert tbl values(10002 , '2018-12-01')  -- 5번 실행


sp_partiton_view 'tbl'



파티션 테이블 에서는 새로 알아야할 명령어 및 개념들이 몇가지 있다.

그리고 인덱스 상관관계 또한 이해해야 할 부분이 있다. 이는, 다음 포스팅때 오늘 실습해본 쿼리를 중심으로 알아보기로 
하겠다.

[##_http://blog.sooli.com/owner/entry/edit/1L%7C2816901162.sql%7C%7C_##]  테스트를 위한 시나리오 , SQL 풀 쿼리이다.(다운로드)



2018/01/31 16:37 2018/01/31 16:37
Posted
Filed under jQuery

ajax 에서 타 도메인(호스트 포함) 호출은 javascript(ajax)에서 SOP 정책위반(same origin policy) 이다.
즉, 같은 도메인 내에서만 호출이 가능하다. 하지만 개발 업무를 하다보면, 내부 또는 외부 API(REST 타입) 또는 페이지 정보 를 호출해야 하는 경우가 있다. 이를 위해서 서버를 허용 (CORS(Cross Origin Resource Sharing)  - Access-Control-Allow-Origin 헤더추가)하도록 설정(W3C 표준)하거나 다른 방법을 강구해야한다.

참고 : 아래는 SOP 정책 준수 와 위반 예제


 호출 URL : http://www.sooli.com/ajax_test/call_ajax.asp   아래 URL들을 호출 할 경우  ↓↓↓↓↓

* SOP 정책 준수
- http://www.sooli.com/data/sample.json   // 호출가능 :)
- http://www.sooli.com/XML/rss.xml  // 호출가능 :)
- http://www.sooli.com/API/REST.asp  // 호출가능 :)
- http://www.sooli.com/php/REST_PHP.php  // 호출가능 :)

* SOP 정책위반
- http://blog.sooli.com:81// 호출 오류 : 도메인은 같으나 포트가 다름  :(
- http://blog.sooli.com/ // 호출 오류 : 호스트가 다름 :(
- https://www.sooli.com/13  // 호출 오류 : 프로토콜이 다름 :(
- http://www.naver.com/mapApi/mapdraw.json  // 호출 오류 : 도메인이 다름 :(


※ 해별방법 : 크로스 도메인 호출 방법 

① 고전적인, iframe proxy
② CORS(Cross Origin Resource Sharing) 명시적 허용
③ 서버 사이드 단, 에서 I/O 방식
④ jQuery  ajax 옵션에서의  jsonp  콜백방식




① 고전적인, Iframe proxy
---------------------------------------------------------------------------------------------------------------------------------

* javascript 수준 + 서버파일 (JSON - ajax 를 이용하지 않음)
iframe proxy 방법의 경우, 개인적으로  예전에 많이 쓰던 방법이다-_-(사실 지금도 간혹쓴다.)

방법은 간단하다. 페이지에 보이지 않게, 히든 iframe 을 두고  그쪽 submit( or 페이지이동) 던져 , iframe 에서  저장 또는 iframe을 무언가를 로딩하면서, DB로 부터가져온 결과를 javascript  의 parent.객체ID 로 접근하여 화면에 반영 또는,  파일 I/O를 통해 읽어드린 내용을 파싱 또는하여 부모창에 반영하는 방법이다.




②. CORS(Cross Origin Resource Sharing) 명시적 허용
----------------------------------------------------------------------------------------------------------------------------------
* JSON - ajax 를 이용함
CORS 의 경우 W3C 의 표준안으로 모든 웹 프로그램 에서 지원한다. 

호출되는 페이지의 상단에 CORS 헤더를 추가하면 호출이 가능해진다. 일종의 타도메인에서 
자신을 호출하는 행위를 허락한다는 의미이다.

아래는 ASP 예시다.(PHP , JSP , .NET  각각 모두 지원함)

<%
    Response.AddHeader "Content-type", "text/xml"
    Response.AddHeader "Access-Control-Allow-Origin", "*"
%>
    ----- 이 부분에 필요 json 형식이든 text 형식이든 출력 한다. ------

<사용방법>
기존의 json 에서의 $.ajax 코딩시 똑같이 호출하면된다.

사내간의 크로스 도메인(호스토포함) 호출이라면, 쉽게 해결될수있는 문제일 수 있다.
(서버페이지의 위 2줄에 대한 코딩삽입에 대한 협업이 간단 할 수 있기때문이다.)
하지만, B2B , 또는 타회사 간의 호출되어지는, 외부 API 로 인경우 정책상 회의를 통해 
협업이 되어야하며, 그게 아닌 공개 API(데이터) 인 경우 CORS 설정이 안되어있을경우는 불가능하다.





③. 서버 사이드 파일 I/O 방식 
---------------------------------------------------------------------------------------------------------------------------------
* JSON - ajax 를 이용함
위의 CORS 가 안되는경우에 사용하는 방식이다. CORS가 허락되지않는 외부API 인경우 
서버 사이드 단 파일 I/O 통해 해결가능하다.

      "  여기서의 핵심은 SOP(same origin policy) 위반은 ajax 에서의 위반이므로, 그것을 피하고,
           서버에서 접근하여 Read & Write 하는  방식이다.   "

--- 생략 ---

// 클라이언트
$.ajax( {
        // url : "http://www.naver.com/api/mapPosition.json", → SOP 위반 호출불가 / 서버에서 호출                  
       url : "/API/CallRef.asp",  →  본인 Url 의 호출이기 때문에 호출가능
})

// 서버단 , /API/CallRef.asp
Set xmlHttp = Server.Createobject("MSXML2.ServerXMLHTTP")  
xmlHttp.Open "GET", "http://www.naver.com/api/mapPosition.json", False
xmlHttp.setRequestHeader "User-Agent", "asp httprequest"
xmlHttp.setRequestHeader "content-type", "application/x-www-form-urlencoded"
xmlHttp.Send
getHTML = xmlHttp.ResponseText
xmlHttp.abort()
set xmlHttp = Nothing
Response.Write(getHTML)  → 내용출력 ajax 가 읽어들임





④ jQuery  ajax 옵션에서의  dataType : "jsonp"  콜백방식
---------------------------------------------------------------------------------------------------------------------------------
ajax 에서는 SOP 정책을 피하기위해  JSONP(Json with Padding)의 콜백방식을 지원한다.
아마다 예전버전에는없었던거같은데, 사실 최근 jquery 를 공부하면서 알게된 방법이다.
백문이불여일견 아래 클라이언트 와 서버를 보자.
(사실, dataType : "jsonp" 방식은 기존의 json , text, html 등 타입방식과 완전 다른방법으로
접근한다. 나중에 기회가 되면 알아보기로하자 or 구글링 하면 다 나온다.)

<클라이언트 side>
$.ajax({

    type : 'GET',
    url : "http://blog.sooli.co.kr/ss.asp" ,
    contentType:"application/x-www-form-urlencoded;char-set:euc-kr",
    dataType : "jsonp",
    jsonpCallback:"callbackData", //  이 부분이 중요 , 
    success:function(data){ parsing(data); } // = success : parsing  같음
});

function parsing(data) {
       $.each(data, function(index, item)
       {
               alert(index);
               alert(item.name); 
               alert(item.tel); 
               alert(item.skill.item1); 
               alert(item.skill.item2);

               alert(item["name"]);           
               alert(item["tel"]); 
               alert(item["skill"]["item1"]); 
               alert(item.skill["item1"]); 
               alert(item["skill"].item2);
         }
      )

}


요즘 툴들이 좋아져서 인텔리센스 덕분에 오타날 확률이 적지만, 그래도 jsonpCallback 타이핑시
"C" 자가 대문자라는점 까먹지말자  jaonpcallback 하면 오류 난다.!!
그리고 jsonpCallback  의 value 인 "callbackData" 이부분도 서버에서 작성할때 대소문자가 같아야 한다.!!

jsonpCallback : 의 value 인 "callbackData" 이부분은 본인이 마음에 드는 아무값이나 작성해도된다

"callbcakData" , "sooliData" , "Data"  , "value123" 등 마음대로 단 서버사이드 wrapping 시 대소문자가 모두 같아야한다.


<서버 side>

위의 클라이언트에서 호출할대 jsonpCallback 에 적혀진 wrapping 용 값이 
서버사이드에서 데이터를 감싸줘야 호출히 오류가 안난다.
jsonpCallback:"callbackData"

즉 서버사이드에서는 json type 으로 값 출력시 
callbackData ( ~~~~~ 데이터 ~~~~ 이런식으로 
감싸줘야(wrapping)한다

아래소스  : http://blog.sooli.co.kr/ss.asp 
----------------------------------------------------------------

callbackData (   // callbackData 시작

[
    {

        "name": "sooli",
        "tel": "010-0000-0000",
        "skill": {
                    "item1": "server",
                    "item2": "mssql"
            }
    }

]

) // callbackData  끝


( 위 4가지 방법말고 다른 방법이 있으며, 알려주시면 좋겟습니다. - 공부하게요 ㄷ )

2018/01/24 14:43 2018/01/24 14:43
Posted
Filed under jQuery

- 당연한 이야기지만 대소문자는 반드시(속성) 구분해야한다.
- ajax 기본 인코딩 utf-8


* Ajax(json) 기본 형식


 $.ajax({


    url : "호출주소", // 자신의 도메인 파일 호출 할 것 (cross domain 기본지원 안함 - " cross-domain 호출하기 편 " 볼것)
    type : "GET" , // GET or POST
    async : true , // 기본 비동기(tr
ue) 동기로 할꺼면 false
    cache : true , // 기본 true (304) false(200)

    data: "데이터" , // 전송할 데이터
                     
       // $('폼아이디').serialize(); - 폼통째로 전달 시리얼라이징
                             // name=데이터&tel=데이터 - 쿼리스트링 방식
                             // data : {'name':'test'} , - json 타입( 바깥 따옴표없다. 안따옴표 필수)


    dataType : // 데이터 타입(응답결과시) xml , html , text , json , jsonp , script ,text
    timeout : 1000 , // 1초 - 서버응답대기시간 설정 (millisecond)

    contentType : // 응답되어 받을 문서의 Type 설정
   
                        (기본 : application/x-wwwform-urlencoded;charset=UTF-8)

    beforeSend : function() { } ,// 전송전 호출할 함수

    complete : function(jqXHR) { } , // 완료수 callback (complete or always)
    success : function(jqXHR) { } , // 성공 후 callback (success or done)
                                                        // jqXHR 안에 결과로온 데이터가 문자열로 들어있음
    error : function(jqXHR) { } , // 오류발생시 callback(error or fail )

 });





데이터 전송 1. data : "데이터" , - 전송할 데이터 array 와 object 로 json 화 하기
dataType : "JSON" 인경우 반드시 stringfy 해야한다.
---------------------------------------------------------------------------------------------------------------------------------------
var a = new Array();
var o = new Object();

o.name = "이름";
o.tel = "010-000-0000";

a.push(o);

var param = JSON.stringify(o); //
JSON.stringify 함수가 {"name" : "이름"} 로 만들어줌

data : param



데이터 전송 2. data : "데이터" - 폼 통째로 전송시 직렬화
----------------------------------------------------------------------------------------------
$('폼아이디').serialize();

data : $('#formID').serialize();



데이터 json 수신 . dateType : "json" 설정
----------------------------------------------------------------------------------------------

클라이언트 호출에 의해서 서버단 API 에서 json 타입으로 리턴 할 경우

* 서버 : JsonArray return;
----------------------------------------------------------------------------------------------
[
    {
   
    "name": "sooli",
        "tel": "010-0000-0000",
        "skill": {
                        "item1": "server",
                        "teim2": "mssql"
                    }
    },
    {
        "name": "pluginn",
        "tel": "010-1111-1111",
        "skill": {
                        "item1": "asp",
                        "item2": "asp.net"
                    }
    }
]
* 클라이언트
----------------------------------------------------------------------------------------------


success : parsing // 참조함수 - delegate 같은느낌


success : function(data){parsing(data);} // 일반함수


function parsing(data)
{
   
    $.each(data, function(index, item)
    {
       

        alert(index);
        alert(item.name);
        alert(item.tel);
        alert(item.skill.item1);
        alert(item.skill.item2)
       
        alert(item["name"]);
        alert(item["tel"]);
        alert(item["skill"]["item1"]);
        alert(item.skill["item1"]);
        alert(item["skill"].item2);
    })
}




* AjaxSetup(json) 같은 페이지에서 ajax를 여러번 쓸경우 셋팅


$.ajaxSetup({

    url : "http://.....",
    type : "POST",
    async : true,
    timeout : 1000,
    error : function() { alert("error");}

});


$.ajax({ // ajaxSetup 상속됨

    success : function(){
   
    // 처리 #1
    }

});


$.ajax({ // ajaxSetup 상속됨

    data : "{}",
    success : function()
    {
   
    // 처리#2
    }

});





* A
jax 각각의 type 방식 호출


$.get( URL , "콜백함수(성공시)" , "데이터타입");
$.post( URL , "콜백함수(성공시)" , "데이터타입");


$.get().done().fail().always(); // 메소드 릴레이 호출가능

done(function(jqXHR){}) , // (done is success)
fail(function(
jqXHR){}) , // (fail is error )
always(function(jqXHR){}) // ( always is always)







* Ajax 이슈


IE 에서 $.ajax 로 같은 Url 호출시 변경되지않은 결과값이 나옴

방법 1 : url : "http://..... ?타임스탬프활용" , // 타임스탬프 및 랜덤 수 를 이용하여 Url fake 줌
방법 2 : 호출 type 을 "POST" 변경 그런데 이 방법의경우 IE 에서는 Cache를 계속 사용하기도 함)
방법 3 : cache : false



* 캐쉬사용안함 설정의 의미,
웹에서의 모든 설정이 마찬가지지만 , cache 설정없음은 304 응답코드 없음을 의미한다.
클라이언트 → 서버요청시 요청한 페이지의 리소스를 캐쉬에서 활용하지 못하고 서버로 부터 모두
다시 받음으로서 속도에 영향을 미칠 수 있다. (단순,text type 이라면, 괜찮을듯 싶다.)

 

2018/01/23 16:49 2018/01/23 16:49