์›น

JSONP

๋™์ผ ์ถœ์ฒ˜ ์ •์ฑ…์„ ์šฐํšŒํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋Š” ๋ ˆ๊ฑฐ์‹œ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ ๊ธฐ์ˆ ์— ๋Œ€ํ•œ ๊ฐ„๋žตํ•œ ์†Œ๊ฐœ

  • #javascript
  • #json
  • #cors
  • #legacy

JSONP๋Š” JSON with Padding์ด๋ผ๊ณ ๋„ ์•Œ๋ ค์ ธ ์žˆ์œผ๋ฉฐ CORS(Cross-Origin Resource Sharing) ์ •์ฑ…์— ์˜ํ•ด ๊ฐ€๋กœ์ฑ„์ง€ ์•Š๊ณ  ๋ฐ์ดํ„ฐ๋ฅผ ์š”์ฒญํ•˜๋Š” ๊ธฐ์ˆ ์ž…๋‹ˆ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ ์ด ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ธŒ๋ผ์šฐ์ €์—์„œ ์‹œํ–‰ํ•˜๋Š” CORS ๊ฒ€์‚ฌ๋ฅผ ์šฐํšŒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚ด ๊ฒฝํ—˜์— ๋”ฐ๋ฅด๋ฉด ๋งŽ์€ ์ค‘๊ตญ ์›น์‚ฌ์ดํŠธ์—์„œ๋Š” ์—ฌ์ „ํžˆ ์ด ๊ธฐ์ˆ ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

๋ถ€์ธ ์„ฑ๋ช…

ํ•œ๊ตญ์–ด ์‹ค๋ ฅ์ด ๋ถ€์ ํ•˜์—ฌ ์ด ๊ธ€์ด ๊ตฌ๊ธ€ ๋ฒˆ์—ญ๊ธฐ๋ฅผ ์ฃผ๋กœ ํ™œ์šฉํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ถ€์ •ํ™•ํ•œ ๋ฌธ๋ฒ•๊ณผ ์–ดํœ˜๊ฐ€ ์žˆ์„์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์  ์–‘ํ•ด ๋ถ€ํƒ๋“œ๋ฆฌ๋ฉฐ, ์ถ”ํ›„์— ๋‹ค์‹œ ๊ฒ€ํ† ํ•˜์—ฌ ์ˆ˜์ •ํ•˜๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

์‹œ๋‚˜๋ฆฌ์˜ค

์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด www.a.com์— ํ˜ธ์ŠคํŒ…๋˜์–ด ์žˆ๊ณ  JavaScript ์ฝ”๋“œ ์ค‘ ํ•˜๋‚˜๊ฐ€ www.b.com์— ํ˜ธ์ŠคํŒ…๋œ ์›๊ฒฉ ์„œ๋ฒ„์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋ ค๊ณ  ํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์›๊ฒฉ ์„œ๋ฒ„๊ฐ€ * ๋˜๋Š” www.a.com์œผ๋กœ ์„ค์ •๋œ Access-Control-Allow-Origin ํ—ค๋”๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ฟผ๋ฆฌ์— ์‘๋‹ตํ•˜์ง€ ์•Š์œผ๋ฉด ๋ธŒ๋ผ์šฐ์ €๋Š” ์‘๋‹ต์„ ์ˆ˜์‹ ํ•˜๊ณ  ํ•ด์„ํ•  ๋•Œ ์˜ค๋ฅ˜๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๊ณ  ๊ฑฐ๋ถ€ํ•ฉ๋‹ˆ๋‹ค. ์š”์ฒญํ•œ ๋ฐ์ดํ„ฐ.

ํ•ด๋ฒ•

์˜ต์…˜ 1: CORS ๊ตฌ์„ฑ

๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๊ฐ€์žฅ ์•ˆ์ „ํ•˜๊ณ  ์ผ๋ฐ˜์ ์ธ ๋ฐฉ๋ฒ•์€ 'Access-Control-Allow-Origin' ํ—ค๋”๊ฐ€ ์ ์ ˆํ•œ ๋„๋ฉ”์ธ์„ ๊ฐ€๋ฆฌํ‚ค๋„๋ก ์„ค์ •ํ•˜์—ฌ ๋ฐฑ์—”๋“œ ์„œ๋ฒ„์—์„œ CORS๋ฅผ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ตฌ์„ฑํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ฆฌ์†Œ์Šค๊ฐ€ Azure, GCP ๋˜๋Š” AWS์™€ ๊ฐ™์€ ํด๋ผ์šฐ๋“œ์—์„œ ํ˜ธ์ŠคํŒ…๋˜๋Š” ๊ฒฝ์šฐ CORS๋ฅผ ํ™œ์„ฑํ™”ํ•˜๋Š” ์„ค์ •๋„ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์˜ต์…˜ 2: JSONP ์‚ฌ์šฉ

JSONP์—๋Š” ์ˆ˜์‹ ๋œ ์‘๋‹ต์„ ํ™œ์šฉํ•˜๊ธฐ ์œ„ํ•ด ๋”ฐ๋ผ์•ผ ํ•˜๋Š” ํŠน์ • ๊ทœ์น™ ์„ธํŠธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

ํฌ๋งท

๋‹ค์Œ์€ https://a.com/sample.json์— ์›์‹œ JSON ํ˜•์‹์˜ ์˜ˆ์ œ ๋ฐ์ดํ„ฐ์ž…๋‹ˆ๋‹ค.

{
  "name": "Jane",
  "age": 14,
  "school": "Stanford High School"
}

๋‹ค์Œ์€ URL https://a.com/sample?callback=callback์— ์žˆ๋Š” JSONP ํ˜•์‹์˜ ๋ฐ์ดํ„ฐ์ž…๋‹ˆ๋‹ค.

callback({
  name: 'Jane',
  age: 14,
  school: 'Stanford High School',
})

๋ณธ์งˆ์ ์œผ๋กœ ์ด๋Š” ์š”์ฒญ๋œ ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ JavaScript ํ•จ์ˆ˜ ํ˜ธ์ถœ์ผ ๋ฟ์ด๋ฉฐ ํ•จ์ˆ˜ ์ด๋ฆ„์€ '์ฝœ๋ฐฑ' ์ฟผ๋ฆฌ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์ˆ˜์ •๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋Š” ์šฐ๋ฆฌ๊ฐ€ "ํŒจ๋”ฉ(Padding)"์ด๋ผ๊ณ  ๋ถ€๋ฅด๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด https://a.com/sample?callback=cb๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ๋ฐ˜ํ™˜๋œ ๋ฐ์ดํ„ฐ๋Š” cb ํ•จ์ˆ˜๋กœ ๋ฌถ์ž…๋‹ˆ๋‹ค.

cb({
  name: 'Jane',
  age: 14,
  school: 'Stanford High School',
})

์ฃผ๋ชฉํ•ด์•ผ ํ•  ํ•œ ๊ฐ€์ง€ ์ค‘์š”ํ•œ ์ฃผ์˜ ์‚ฌํ•ญ์€ ์ œ๊ณต๋œ ์ฝœ๋ฐฑ ํ•จ์ˆ˜ ์ด๋ฆ„์ด ๋ฌด์—‡์ด๋“  ์ œ๊ณต๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์˜๋ฏธ ์žˆ๊ฒŒ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ํ•จ์ˆ˜๊ฐ€ ์กด์žฌํ•ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

Uncaught ReferenceError: <method> is not defined

์šฉ๋ฒ•

์š”์ฒญ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ์ฟผ๋ฆฌ ๋งค๊ฐœ๋ณ€์ˆ˜์— ์ œ๊ณต๋œ ๋™์ผํ•œ ์ด๋ฆ„์œผ๋กœ JavaScript ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•˜๊ณ  JSONP ๋ฐ์ดํ„ฐ๊ฐ€ ๋กœ๋“œ๋˜๊ธฐ ์ „์— ํ•จ์ˆ˜๊ฐ€ ์ •์˜๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”.

function callback(data) {
  // ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌ
  console.log(data)
}

HTML๋กœ ์‡ผ์ผ€์ด์Šค

HTML์—์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

<!DOCTYPE html>
<html>
  <head>
    <title>JSONP Showcase</title>
  </head>
  <body>
    <script type="text/javascript">
      function myFunction(data) {
        console.log(data)
      }
    </script>

    <!-- ์ผ๋ฐ˜ JavaScript์ฒ˜๋Ÿผ ์Šคํฌ๋ฆฝํŠธ ํƒœ๊ทธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ JSONP ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ -->
    <script
      type="text/javascript"
      src="https://a.com/mydata?callback=myFunction"
    ></script>
  </body>
</html>

์บ์‹œ ํ•ด์ œ

JSONP ํ˜ธ์ถœ์€ <script src="https://constant-static-url">์ด ์ƒ์ˆ˜์ธ ๊ฒฝ์šฐ ์ตœ์ ํ™”๋ฅผ ์œ„ํ•ด ๋ธŒ๋ผ์šฐ์ €์— ์˜ํ•ด ์บ์‹ฑ๋ฉ๋‹ˆ๋‹ค. ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์˜ค๋ž˜๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์บ์‹ฑํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๋ ค๋ฉด Math.random์„ ์‚ฌ์šฉํ•˜์—ฌ ์ฝœ๋ฐฑ ํ•จ์ˆ˜ ์ด๋ฆ„์„ ๋™์ ์œผ๋กœ ์ƒ์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

window.onload = function () {
  var randomNum = Math.floor(100_000 * Math.random())
  var functionName = 'cb_' + randomNum

  window[functionName] = function (data) {
    console.log(data)
  }

  // ์Šคํฌ๋ฆฝํŠธ ํƒœ๊ทธ๋ฅผ ๋™์ ์œผ๋กœ ์ƒ์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  var newScriptTag = document.createElement('script')
  newScriptTag.src = 'https://a.com/mydata?callback=' + functionName

  document.body.appendChild(newScriptTag)
}

์ด ์ ‘๊ทผ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ธŒ๋ผ์šฐ์ €๋Š” ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ ์ตœ์‹  ๋ฐ์ดํ„ฐ๋ฅผ ์š”์ฒญํ•ฉ๋‹ˆ๋‹ค.

์ฒญ์†Œ

๋ธŒ๋ผ์šฐ์ €์—์„œ ์ด๋ฏธ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์œผ๋ฏ€๋กœ ๋™์ ์œผ๋กœ ์ƒ์„ฑ๋œ ์Šคํฌ๋ฆฝํŠธ ํƒœ๊ทธ๋ฅผ ์„ ํƒ์ ์œผ๋กœ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

window.onload = function () {
  var randomNum = Math.floor(100_000 * Math.random())
  var functionName = 'cb_' + randomNum

  window[functionName] = function (data) {
    console.log(data)
  }

  // ์Šคํฌ๋ฆฝํŠธ ํƒœ๊ทธ๋ฅผ ๋™์ ์œผ๋กœ ์ƒ์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  var newScriptTag = document.createElement('script')
  newScriptTag.id = 'script_' + functionName
  newScriptTag.src = 'https://a.com/mydata?callback=' + functionName

  document.body.appendChild(newScriptTag)
  document.getElementById(newScriptTag.id).remove()
}

์ •๋ฆฌ๋ฅผ ํ†ตํ•ด JSONP ํ˜ธ์ถœ์ด ์›ํ™œํ•˜๊ฒŒ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

์žฅ์ ๊ณผ ๋‹จ์ 

์žฅ์ 

  • ํฌ๋กœ์Šค ๋„๋ฉ”์ธ ์š”์ฒญ: CORS ์ •์ฑ…์— ์˜ํ•ด ์‹œํ–‰๋˜๋Š” ๊ฒฝ๊ณ„๋ฅผ ๋ฒ—์–ด๋‚  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์‚ฌ์šฉํ•˜๊ธฐ ์‰ฌ์›€: ๋ณต์žกํ•œ ์„ค์ • ์ฝ”๋“œ ์—†์ด HTML์—์„œ <script> ํƒœ๊ทธ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.
  • ๋›ฐ์–ด๋‚œ ๋ธŒ๋ผ์šฐ์ € ํ˜ธํ™˜์„ฑ: ๋‹จ์ˆœํ•œ JavaScript ํ•จ์ˆ˜ ํ˜ธ์ถœ์ด๊ธฐ ๋•Œ๋ฌธ์— ๋ชจ๋“  ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

๋‹จ์ 

  • ๋ณด์•ˆ์œ„ํ—˜ : ์ทจ์•ฝํ•œ ํŠน์„ฑ์œผ๋กœ ์ธํ•ด ์•…์„ฑ์ฝ”๋“œ์— ์˜ํ•ด ์•…์šฉ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ ์—†์Œ: ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•œ ๊ฒฝ์šฐ. ํ•จ์ˆ˜๊ฐ€ ์ •์˜๋˜์ง€ ์•Š์•˜๊ฑฐ๋‚˜ ์„œ๋ฒ„๊ฐ€ ์‘๋‹ตํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ ํ•ด๋‹น ์˜ค๋ฅ˜๋ฅผ ์ฝ˜์†”์— ํ‘œ์‹œํ•˜๋Š” ๊ฒƒ ์™ธ์—๋Š” ์˜ค๋ฅ˜๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์—†์Šต๋‹ˆ๋‹ค.
  • ์„œ๋ฒ„์— ๋”ฐ๋ผ ๋‹ค๋ฆ„: ์„œ๋ฒ„๊ฐ€ JSONP ์—”๋“œํฌ์ธํŠธ๋ฅผ ์ œ๊ณตํ•˜์ง€ ์•Š์œผ๋ฉด JSONP๋ฅผ ์‚ฌ์šฉํ•  ๋ฐฉ๋ฒ•์ด ์—†์Šต๋‹ˆ๋‹ค.
  • GET ์š”์ฒญ๋งŒ ์ง€์›: JSONP ์š”์ฒญ์€ <script> ํƒœ๊ทธ๋งŒ ์‚ฌ์šฉํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์ด๋ฏธ ์•Œ๊ณ  ์žˆ์œผ๋ฏ€๋กœ GET ์ด์™ธ์˜ ๋‹ค๋ฅธ HTTP ๋ฉ”์„œ๋“œ๋ฅผ ์ง€์›ํ•  ๋ฐฉ๋ฒ•์€ ์—†์Šต๋‹ˆ๋‹ค.

์ฐธ๊ณ 

JSONP.ย Wikipedia. Retrieved 2024, March 24 from https://en.wikipedia.org/wiki/JSONP
Maccana, M., Cheeso. What is JSONP, and why was it created?https://stackoverflow.com/questions/2067472/what-is-jsonp-and-why-was-it-created
Cieล›lar, M. JSONP demystified: What it is and why it exists.ย LogRocket. https://blog.logrocket.com/jsonp-demystified-what-it-is-and-why-it-exists/
Vinod. Understanding JSONP.https://www.youtube.com/watch?v=3AoeiQa8mY8