Axios: ์‚ฌ์ดํŠธ ๊ฐ„ POST๋ฅผ ์ž‘๋™ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

์— ๋งŒ๋“  2016๋…„ 01์›” 11์ผ  ยท  70์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: axios/axios

์•ˆ๋…•ํ•˜์„ธ์š”,

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

  • ํฌ๋กœ์Šค ๋„๋ฉ”์ธ: ์ฐธ
  • xDomain: ์‚ฌ์‹ค
    *xDomainRequest: ์ฐธ

๊ตฌ์„ฑ์—. ๊ทธ๋ฆฌ๊ณ  ๊ทธ๋“ค ์ค‘ ๋ˆ„๊ตฌ๋„ ์ผํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. (์ด ๊ธฐ๋Šฅ์„ ์‹ค์ œ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ ์ถ”๊ฐ€ ์ •๋ณด๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋ฉด ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.)

์ตœ๋Œ€ํ•œ ๋นจ๋ฆฌ ์กฐ์–ธ ๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค. ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

์–ด๋–ป๊ฒŒ ๊ทธ๋Ÿฐ ๊ฑฐ๋Œ€ํ•œ ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜์ง€ ์•Š์Šต๋‹ˆ๊นŒ?

๋ชจ๋“  70 ๋Œ“๊ธ€

๋˜ํ•œ ๊ตฌ์„ฑ์—์„œ withCredentials๋ฅผ true๋กœ ์„ค์ •ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฐฉ๊ธˆ ์ด ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์œผ๋ฉฐ Mac์—์„œ๋งŒ ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋‚ด ๋„คํŠธ์›Œํฌ๋ฅผ ๋””๋ฒ„๊น…ํ•˜๋ ค๊ณ  ๋ฐค๋‚ฎ์œผ๋กœ ์ข‹์€ ์‹œ๊ฐ„์„ ๋ณด๋ƒˆ๊ณ  ๋ฐ”๋‹๋ผ XHR ์š”์ฒญ์„ ์‚ฌ์šฉํ•˜์—ฌ ์ด๊ฒƒ์„ ์‹œ๋„ํ•˜๊ธฐ๋กœ ๊ฒฐ์ •ํ–ˆ๊ณ  ๋ฌธ์ œ๊ฐ€ ๋‚ด ๋„คํŠธ์›Œํฌ๊ฐ€ ์•„๋‹ˆ๋ผ axios๋ผ๋Š” ๊ฒƒ์„ ๊นจ๋‹ฌ์•˜์Šต๋‹ˆ๋‹ค.

๋‚˜๋„ ์ž๊ฒฉ ์ฆ๋ช…์ด true๋กœ ์„ค์ •๋œ ๊ต์ฐจ ์‚ฌ์ดํŠธ ์š”์ฒญ์„ ์ˆ˜ํ–‰ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋„คํŠธ์›Œํฌ ์š”์ฒญ์„ ๋ณด๋ฉด ERR_EMPTY_RESPONSE๊ฐ€ ํ‘œ์‹œ๋˜๋ฉฐ ๋ธŒ๋ผ์šฐ์ €๋ฅผ ๋– ๋‚˜๊ธฐ๋„ ์ „์— ์š”์ฒญ์ด ์‹คํŒจํ•œ ๊ฒƒ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ๋‚ด ๊ตฌ์„ฑ์ž…๋‹ˆ๋‹ค.

const myApi = axios.create({
  baseURL: 'http://someUrl/someEndpoint',
  timeout: 10000,
  withCredentials: true,
  transformRequest: [(data) => JSON.stringify(data.data)],
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json',
  }
});'

๊ธฐํšŒ๊ฐ€ ๋œ๋‹ค๋ฉด ์ด ๋ถ€๋ถ„์— ๋Œ€ํ•ด ๋” ์•Œ์•„๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

์•„, ์ œ์ •์‹ ์ด ์•„๋‹ˆ๊ตฌ๋‚˜. :) ๊ฐ€๋Šฅํ•˜๋ฉด ์ด๊ฒƒ์„ ์‚ดํŽด๋ณด์‹ญ์‹œ์˜ค.

๋‚ด ๋ฌธ์ œ๋Š” Axios์™€ ๊ด€๋ จ์ด ์—†๋Š” ๊ฒƒ์œผ๋กœ ๋‚˜ํƒ€๋‚ฌ์Šต๋‹ˆ๋‹ค. Cisco Anyconnect๊ฐ€ ๋‚ด ์‹œ์Šคํ…œ์˜ ์˜ต์…˜ ์š”์ฒญ์„ ์ฐจ๋‹จํ•˜๊ณ  ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ์ด์œ ๊ฐ€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

๊ต์ฐจ ๋„๋ฉ”์ธ ์š”์ฒญ์—๋Š” ์ถ”๊ฐ€ ๊ตฌ์„ฑ์ด ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด์ „ IE์˜ ๊ฒฝ์šฐ XDomainRequest ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋Œ€์ฒด๋ฉ๋‹ˆ๋‹ค. https://github.com/mzabriskie/axios/blob/master/lib/adapters/xhr.js#L22

๋” ์ž์„ธํ•œ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ์–ด๋–ค ๋ธŒ๋ผ์šฐ์ €, OS, axios ๋ฒ„์ „, ๋ชจ๋“  ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€.

Jenny์— ๋Œ€ํ•ด ๋งํ•  ์ˆ˜๋Š” ์—†์ง€๋งŒ ํŠนํžˆ ์ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” Cisco Anyconnect ๊ธฐ๋ณธ ๋ณด์•ˆ์— ์˜ํ•ด ์š”์ฒญ์ด ์ฐจ๋‹จ๋˜๋„๋ก ํ•˜๋ฏ€๋กœ ๋‹ค๋ฅธ ๋ณด์•ˆ ์„ค์ •์—์„œ๋„ ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ์ด๊ฒƒ์„ ์ถ”์ ํ•˜๋ ค๊ณ  ๋…ธ๋ ฅํ•˜๊ณ  ์žˆ์ง€๋งŒ ์ง€๊ธˆ๊นŒ์ง€๋Š” ์šด์ด ์—†์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ cisco Anyconnect ๋ฐ ๊ธฐํƒ€ VPN ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์„ค์น˜๋œ Mac์—์„œ ์‚ฌ์ดํŠธ ๊ฐ„ ์š”์ฒญ์„ ๋งŒ๋“ค์–ด ์žฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚ด ํ™˜๊ฒฝ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • ์•ก์‹œ์˜ค์Šค 0.8.1
  • ์—˜ ์บํ”ผํƒ„
  • ํฌ๋กฌ
  • ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€: "์š”์ฒญํ•œ ๋ฆฌ์†Œ์Šค์— 'Access-Control-Allow-Origin' ํ—ค๋”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ Origin ' http://localhost :3000'์€(๋Š”) ์•ก์„ธ์Šค๊ฐ€ ํ—ˆ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."

๋™์ผํ•œ ์š”์ฒญ์ด curl์—์„œ๋„ ์ž‘๋™ํ•œ๋‹ค๋Š” ์ ์— ์œ ์˜ํ•˜์‹ญ์‹œ์˜ค.

์กฐ์‚ฌํ•ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!

CORS๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์š”์ฒญ์ด ํ—ˆ์šฉ๋˜๋Š”์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ์„œ๋ฒ„์— ์‹คํ–‰ ์ „ ์š”์ฒญ์ด ์ด๋ฃจ์–ด์ง‘๋‹ˆ๋‹ค. ๋ชจ๋“  ์ถœ์ฒ˜์˜ ์š”์ฒญ์„ ํ—ˆ์šฉํ•˜๋Š” Acces-Control-Allow-Origin: * ํ—ค๋”๋ฅผ ์„ค์ •ํ•˜์—ฌ ์š”์ฒญ ๋ฐฉ๋ฒ•์œผ๋กœ OPTIONS ๊ฐ€ ์žˆ๋Š” ์š”์ฒญ์— ์„œ๋ฒ„๊ฐ€ ์‘๋‹ตํ•˜๋„๋ก ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋˜๋Š” ํŠน์ • ์ถœ์ฒ˜ Acces-Control-Allow-Origin: http://example.com ๋งŒ ํ—ˆ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋„ค, ์ดํ•ดํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์„œ๋ฒ„๋Š” ๋‚ด ๊ฒƒ์ด ์•„๋‹™๋‹ˆ๋‹ค. Baas(backend-as-a-service)๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ทธ๋“ค์€ ์ด๋ฏธ ๋‚ด ๋„๋ฉ”์ธ์„ ํ—ˆ์šฉ ๋ชฉ๋ก์— ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค. Baas๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์€ ๊ทธ๋Ÿฐ ๋ฌธ์ œ๊ฐ€ ์—†์—ˆ๋Š”์ง€ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋‹น์‹ ์ด ์ œ๊ณตํ•œ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ๋ฌด์‹œํ•  ๊ฒƒ์ด์ง€๋งŒ, ๊ทธ๊ฒƒ์— ๋”ฐ๋ฅด๋ฉด ๋‹น์‹ ์ด baas๊ฐ€ ๋‹น์‹ ์„ ์œ„ํ•ด ์ผํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋“ค๋ฆฌ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ต์ฐจ ์ถœ์ฒ˜ ๋ณด์•ˆ์€ ๋ธŒ๋ผ์šฐ์ € ๋‚ด์˜ ์ œํ•œ ์‚ฌํ•ญ์ผ ๋ฟ์ด๋ฏ€๋กœ curl์„ ์‚ฌ์šฉํ•˜๋ฉด ์‹คํŒจํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋ธŒ๋ผ์šฐ์ €์—์„œ ๋„คํŠธ์›Œํฌ ํƒญ์„ ์—ด๊ณ  OPTIONS ์š”์ฒญ์— ๋Œ€ํ•œ ์‘๋‹ต์œผ๋กœ ์–ป์€ ๊ฒƒ์„ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ์‘๋‹ต ๋ฐ์ดํ„ฐ์™€ ํ—ค๋”๋ฅผ ๋ณด๋Š” ๊ฒƒ์ด ์ด ๋ฌธ์ œ๋ฅผ ๋””๋ฒ„๊ทธํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋˜๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค.

๊ฐ์‚ฌ ํ•ด์š”

ํ—ค๋”๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

image

๋‹ค์Œ์€ axios๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ API์—์„œ ๋‚ด ์‚ฌ์šฉ์ž ํ”„๋กœํ•„์„ ๊ฐ€์ ธ์˜ฌ ๋•Œ GitHub์˜ ์‘๋‹ต ํ—ค๋”์ž…๋‹ˆ๋‹ค.

screen shot 2016-01-19 at 11 36 54 am

GitHub์—์„œ Access-Control-Allow-Origin: * ์ถ”๊ฐ€ํ•œ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Baas์˜ ์‘๋‹ต์— Access-Control ์œ ํ˜• ํ—ค๋”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

์•Œ๊ฒ ์Šต๋‹ˆ๋‹ค ํ . ๋‹ต๋ณ€์ด ์—„์ฒญ๋‚˜๊ฒŒ ๋Šฆ์–ด ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค. ์ด์— ๋Œ€ํ•ด ์กฐ๊ธˆ ๋” ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋งค์šฐ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

๋‚ด๊ฐ€๋ณด๊ณ ์žˆ๋Š” ๊ฒƒ์ด ๊ด€๋ จ์ด ์žˆ๋Š”์ง€ ์—ฌ๋ถ€๋Š” ํ™•์‹คํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ ์›๊ฒฉ ์„œ๋ฒ„์— ์ธ์ฆ ์š”์ฒญ์„ ๋ณด๋‚ด๊ณ  ์ฟ ํ‚ค๋ฅผ ๋‹ค์‹œ ๋ฐ›์„ ์ˆ˜ ์žˆ์ง€๋งŒ ์„œ๋ฒ„์— ๋Œ€ํ•œ ํ›„์† ํ˜ธ์ถœ์€ ์ฟ ํ‚ค์™€ ํ•จ๊ป˜ ์ฟ ํ‚ค๋ฅผ ๋ณด๋‚ด์ง€ _์•Š์œผ๋ฏ€๋กœ_ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ์€ ๋กœ๊ทธ์ธ์„ ์œ„ํ•œ POST ํ˜ธ์ถœ์˜ ํ—ค๋”์ž…๋‹ˆ๋‹ค.
login

๊ทธ๋ฆฌ๊ณ  ์ด์ œ ํ›„์† GET ํ˜ธ์ถœ:
verify

origin ์•„๋ž˜ ๋‚˜์—ด๋œ IP ์ฃผ์†Œ๋Š” ์ œ ์†Œ์œ ์ด๋ฏ€๋กœ ๋ฌธ์ œ๊ฐ€ ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด ์œ„์น˜๊ฐ€ ์ž˜๋ชป๋œ ๊ฒฝ์šฐ ์ƒˆ ๋ฌธ์ œ๋ฅผ ๋งŒ๋“ค๊ฑฐ๋‚˜ ์ ์ ˆํ•œ ๊ธฐ์กด ๋ฌธ์ œ์— ์ฒจ๋ถ€ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

์ƒˆ๋กœ์šด ์ฃผ๋ฆ„์œผ๋กœ; ์ง์„  XHR์„ ์‚ฌ์šฉํ•˜์—ฌ ํ›„์† GET ํ˜ธ์ถœ์„ ํ…Œ์ŠคํŠธํ–ˆ์œผ๋ฉฐ ์ฟ ํ‚ค๊ฐ€ ์ œ๋Œ€๋กœ ์ „์†ก๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ Axios๋ฅผ ํ†ตํ•ด ๋™์ผํ•œ ํ˜ธ์ถœ์„ ์ˆ˜ํ–‰ํ•˜๋ฉด ์œ„์—์„œ ์–ธ๊ธ‰ํ•œ ๋™์ผํ•œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

์–ด. ๋ฌด์‹œํ•˜์‹ญ์‹œ์˜ค - Axios๋ฅผ ํ†ตํ•ด ์˜ˆ์ƒ๋Œ€๋กœ ๋ฌผ๊ฑด์„ ๋ณด๋‚ด์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. :)

์ €๋„ ๊ฐ™์€ ๋ฌธ์ œ์— ์ง๋ฉดํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
OPTIONS ํ˜ธ์ถœ์€ ํ†ต๊ณผํ•˜์ง€๋งŒ POST ํ˜ธ์ถœ์€ cors์— ๋ฉˆ์ถฅ๋‹ˆ๋‹ค.
http://stackoverflow.com/questions/36907693/axios-cors-issue-with-github-oauth-not-getting-access-token

์–ด๋–ป๊ฒŒ ๊ทธ๋Ÿฐ ๊ฑฐ๋Œ€ํ•œ ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜์ง€ ์•Š์Šต๋‹ˆ๊นŒ?

+1

+1

+1

+1

+1

+1

+1

@dsacramon ๋‹น์‹ ์ด ๋ณด๊ณ  ์žˆ๋Š” ๋ฌธ์ œ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ๋ณด๊ณ ๋˜๋Š” ๋ฌธ์ œ์˜ ๋Œ€๋ถ€๋ถ„์€ ์„œ๋ฒ„ ๋ฌธ์ œ๋‚˜ ์˜ค๊ฒฝ๋ณด ๋ฌธ์ œ์ธ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ๋ณผ ์ˆ˜ ์žˆ๋Š” ์žฌํ˜„ ๊ฐ€๋Šฅํ•œ ์˜ค๋ฅ˜๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ์ˆ˜์ • ์ž‘์—…์„ ํ•˜๊ฒŒ ๋˜์–ด ๊ธฐ์ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ๋„ ๋ฐ›๊ณ 

XMLHttpRequest๋Š” https://en.wikipedia.org/w/api.php?action=opensearch&format=json&search=fish๋ฅผ ๋กœ๋“œํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค http://localhost :3000'์€ ์•ก์„ธ์Šค๊ฐ€ ํ—ˆ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋˜ํ•œ fetch to note๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ทธ๊ฒƒ์˜ ํฌ๋กฌ์ด ์ตœ๊ทผ์— ๊ทธ๋“ค์˜ ์š”์ฒญ ์„ค์ • ์ •์ฑ…์„ ๋” ์—„๊ฒฉํ•˜๊ฒŒ ๋งŒ๋“ค์—ˆ๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค. ๋‚˜๋Š” ๊ทธ๊ฒƒ์ด ์–ด๋–ค ์ข…๋ฅ˜์˜ ํ—ค๋”๊ฐ€ ํ•„์š”ํ•  ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•œ๋‹ค.

๋‹ค์Œ์€ ๋ช‡ ๊ฐ€์ง€ ์˜ˆ์ž…๋‹ˆ๋‹ค(๋‘˜ ๋‹ค https๋ฅผ ํ†ตํ•ด ์ œ๊ณต๋จ)

์˜ˆ 1 - ์ž˜ ์ž‘๋™

axios.get('https://randomuser.me/api/')
  .then(function (response) {
    console.log(response.data);
  })
  .catch(function (error) {
    console.log(error);
  });

์˜ˆ์ œ 2 - ์ž‘๋™ํ•˜์ง€ ์•Š์Œ - ์˜ค๋ฅ˜ ํ‘œ์‹œ ?

axios.get('https://en.wikipedia.org/w/api.php?action=opensearch&format=json&search=fish')
  .then(function (response) {
    console.log(response.data);
  })
  .catch(function (error) {
    console.log(error);
  });

์—ฌ๊ธฐ์— ์˜ค๋ฅ˜ ์‘๋‹ต์ด ์žˆ์Šต๋‹ˆ๋‹ค

[object Error] {
  config: [object Object] {
    data: undefined,
    headers: [object Object] { ... },
    maxContentLength: -1,
    method: "get",
    timeout: 0,
    transformRequest: [object Object] { ... },
    transformResponse: [object Object] { ... },
    url: "https://en.wikipedia.org/w/api.php?action=opensearch&format=json&search=fish",
    validateStatus: function validateStatus(status) {
      return status >= 200 && status < 300;
    },
    xsrfCookieName: "XSRF-TOKEN",
    xsrfHeaderName: "X-XSRF-TOKEN"
  },
  response: undefined
}

๊ด€๋ จ์ด ์žˆ์„ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด transformResponse ์— ์žˆ์Šต๋‹ˆ๊นŒ? PROTECTION_PREFIX ๋น„ํŠธ๊ฐ€ ๋ฌด์—‡์„ ์˜๋ฏธํ•˜๋Š”์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค.

[object Object] {
  0: function transformResponse(data) {
      /*eslint no-param-reassign:0*/
      if (typeof data === 'string') {
        data = data.replace(PROTECTION_PREFIX, '');
        try {
          data = JSON.parse(data);
        } catch (e) { /* Ignore */ }
      }
      return data;
    }
}

๋…ธ๋ ฅํ•˜๋Š” ๊ฒƒ์กฐ์ฐจ

๋ชจ๋“œ: '๋…ธ์ฝ”๋ฅด'
๊ฐ€์ ธ ์˜ค๊ธฐ์—์„œ ์—ฌ์ „ํžˆ์ด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋Œ€๋‹ต์ด ๋งค์šฐ ๊ฐ„๋‹จํ•˜๊ณ  ์ผ์ข…์˜ ํ—ค๋”๊ฐ€ ํ•„์š”ํ•˜๋‹ค๊ณ  ํ™•์‹ ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋งŒ ๊ทธ๊ฒƒ์ด ๋ฌด์—‡์ธ์ง€๋Š” ํ™•์‹คํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ณ„์†ํ•ด์„œ ๋†€๊ณ  ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

wikipedia api๋Š” ์ด์ƒํ•œ ์˜ˆ์ผ ์ˆ˜ ์žˆ์œผ๋ฉฐ ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์—๊ฒŒ๋„ ๋™์ผํ•œ ์˜ค๋ฅ˜๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ?

์ด ์ฝ”๋“œ๋ฅผ ์‚ญ์ œํ•˜๋ฉด ์ž‘๋™ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. axios.defaults.withCredentials = true

jsonp ์™€ ์ž˜ ์ž‘๋™ํ•˜๋„๋ก wikipedia API๋ฅผ ์–ป์—ˆ์Šต๋‹ˆ๋‹ค.

var jsonp = require('jsonp');

// search for 'frog'
jsonp('https://en.wikipedia.org/w/api.php?action=opensearch&search=frog&format=json', null, function (err, data) {
  if (err) {
    console.error(err.message);
  } else {
    console.log(data);
  }
});

์ถ”๊ฐ€ ๊ตฌ์„ฑ์ด ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

axios์™€ ๋™์ผํ•œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ๋‚ด React ๊ตฌ์„ฑ ์š”์†Œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

import React, { Component } from 'react'
import axios from 'axios'

export default class User extends Component {
  constructor(props){
    super(props)

    // axios.defaults.withCredentials = true

    const config = {
    method: 'get',
    url: 'https://api.airbnb.com/v2/users/2917444?client_id=3092nxybyb0otqw18e8nh5nty&_format=v1_legacy_show',
    headers: {'X-Requested-With': 'XMLHttpRequest'},
    responseType: 'json',
    withCredentials: true,
  }

    axios.request(config)
      .then(response => { console.log('response: ', response) });

  }

  render() {
    return (
      <div>User</div>
    )
  }
}

_์ฐธ๊ณ : Node ์š”์ฒญ์œผ๋กœ API๋ฅผ ์™„๋ฒฝํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค._

@Sinistralis ์™€ ๋™์ผํ•œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. Mac OSX์˜ ์ตœ์‹  ๋ฒ„์ „์˜ ํฌ๋กฌ์—์„œ ์ œ๋Œ€๋กœ ์ž‘์„ฑ๋œ CORS ์š”์ฒญ์— ๋Œ€ํ•ด net::ERR_EMPTY_RESPONSE ๋ฅผ ๋ฐ›๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค(๋‚ด ์„œ๋ฒ„๋Š” OPTIONS๋ฅผ ํฌํ•จํ•œ ๋ชจ๋“  CORS ํ—ค๋”๋ฅผ ์ž˜ ์ฒ˜๋ฆฌํ•จ). iOS10 ์‚ฌํŒŒ๋ฆฌ์—์„œ๋Š” ๋˜‘๊ฐ™์€ ์ฝ”๋“œ๊ฐ€ ๋ฌธ์ œ ์—†์ด ์ž‘๋™ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด์ƒํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ๊ฐ€ ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐ๋  ์ˆ˜ ์žˆ๋Š”์ง€ ์•Œ์•„๋ณด๊ธฐ ์œ„ํ•ด ์กฐ๊ธˆ ๋” ์ง์ ‘ ์กฐ์‚ฌํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

์ตœ์‹  ๋ฒ„์ „์˜ ํฌ๋กฌ์ด ์„ค์น˜๋œ ์ด์ „ Mac(10.11)์—์„œ ์ •ํ™•ํžˆ ๋™์ผํ•œ ์ฝ”๋“œ๋กœ ์ด ์˜ค๋ฅ˜๋ฅผ ์žฌํ˜„ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์ฐธ์œผ๋กœ ๋งค์šฐ ์ด์ƒํ•ฉ๋‹ˆ๋‹ค. ๋งค์šฐ ๊ฐ„๋‹จํ•œ ์•ฑ์ธ http://lights.suyashkumar.com ์„ ๋ฐฉ๋ฌธํ•˜์—ฌ ์ฝ˜์†”์„ ๊ฒ€์‚ฌํ•˜์—ฌ ์žฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(์ฝ”๋“œ๋Š” ์—ฌ๊ธฐ์— ์žˆ์Šต๋‹ˆ๋‹ค . ์ผ๋ถ€ ์ปดํ“จํ„ฐ์—์„œ๋Š” ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๊ณ  ๋กœ๊ทธ์ธ์œผ๋กœ ๋ฆฌ๋””๋ ‰์…˜๋ฉ๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์ปดํ“จํ„ฐ์—์„œ๋Š” ๋ฆฌ๋””๋ ‰์…˜๋˜์ง€ ์•Š๊ณ  ๊ธฐ๋ณธ ํŽ˜์ด์ง€์— ๋‚จ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๋‚ด ์˜ค๋ฅ˜๋ฅผ ํ•ด๊ฒฐํ–ˆ์Šต๋‹ˆ๋‹ค. ์ €์—๊ฒŒ๋Š” config.headers ์˜ ํ—ค๋”๋ฅผ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹œ์ž‘ ์‹œ null ๊ฐ’์œผ๋กœ ํ• ๋‹นํ•˜๋Š” ๊ฒƒ๊ณผ ๊ด€๋ จ๋œ ๋ฌธ์ œ์˜€์Šต๋‹ˆ๋‹ค(๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€์—์„œ ๊ฐ’์„ ๊ฐ€์ ธ์˜ค๊ณ  ์ฒ˜์Œ์—๋Š” ์•„๋ฌด ๊ฒƒ๋„ ์—†์Œ). ๊ฐ’์ด null์ผ ๋•Œ ๊ฐ’์„ ๋นˆ ๋ฌธ์ž์—ด๋กœ ํ• ๋‹นํ•˜๋ฉด ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด axios ๋‚ด์—์„œ ์ฒ˜๋ฆฌ๋  ์ˆ˜ ์žˆ๊ฑฐ๋‚˜ ์ฒ˜๋ฆฌ๋˜์–ด์•ผ ํ•˜๋Š” ํ•ญ๋ชฉ์ธ์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค(_๊ฐ€๋”_ ์ค‘๋‹จ๋˜๋Š” ๊ฒฝ์šฐ xhr์— null ํ—ค๋”๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๋ฐ ๊ฐ’์ด ์žˆ๋Š”์ง€ ํ™•์‹คํ•˜์ง€ ์•Š์Œ).

๋น„์Šทํ•œ ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์˜ ๊ฒฝ์šฐ ์ผ๋ถ€ VPN ํด๋ผ์ด์–ธํŠธ๋„ OPTIONS ์š”์ฒญ์„ ์ฐจ๋‹จํ•  ์ˆ˜ ์žˆ์Œ์„ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค( ์—ฌ๊ธฐ ์ฐธ์กฐ).

์˜คํ•ด์˜ ์†Œ์ง€๊ฐ€ ์žˆ๋Š” CORS ์˜ค๋ฅ˜๋Š” ์—ฌ์ „ํžˆ ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค. fetch ํด๋ฆฌํ•„์€ ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด mode: 'no-cors' ๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๊ฐ€ ์šด์˜ํ•˜๋Š” ๋‹ค๋ฅธ ํ™˜๊ฒฝ์˜ ์‹œ์Šคํ…œ๊ณผ ๋‹ค๋ฅธ ํฌํŠธ์˜ ๋™์ผํ•œ ์‹œ์Šคํ…œ์— ๋Œ€ํ•ด ์š”์ฒญํ•˜๋ ค๋ฉด ์ด๋Ÿฌํ•œ ์ข…๋ฅ˜์˜ ์š”์ฒญ์„ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค!

@dreki ์–ธ๊ธ‰ํ•œ ๋ฌธ์ œ์— ๋Œ€ํ•œ ์„ค๋ช…์„ ์ œ๊ณตํ•˜์‹ญ์‹œ์˜ค.

์„œ๋ฒ„๊ฐ€ ๋‹จ์ˆœํžˆ ์˜ค๋ฆฌ์ง„์˜ ์š”์ฒญ์„ ์ˆ˜๋ฝํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ ํด๋ผ์ด์–ธํŠธ ์ธก์—์„œ๋Š” ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋‹น์‹ ์ด ํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ์šฐ๋ฆฌ๋Š” ์—ฌ๊ธฐ์— ์—„์ฒญ๋‚œ ๋ณด์•ˆ ๋ˆ„์ถœ์ด ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค(๊ทธ๋ฆฌ๊ณ  "์šฐ๋ฆฌ"๋Š” ์ธํ„ฐ๋„ท ์ „์ฒด๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค)...

๋‚˜๋Š” axios๊ฐ€ ์—ฌ๊ธฐ์—์„œ ์™„์ „ํžˆ ์ผ์น˜ํ•˜๊ฒŒ ํ–‰๋™ํ•˜๊ณ  ๋ฐ˜์‘ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

์ค‘์š”ํ•œ ์‘๋‹ต ํ—ค๋”๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์ด ์„œ๋ฒ„ ์ธก ์„œ๋น„์Šค๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋Š” ์œ ํšจํ•œ ์ถœ์ฒ˜๋ฅผ ์„ค์ •ํ•˜๋Š” Access-Control-Allow-Origin ์ž…๋‹ˆ๋‹ค. ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ด๋Ÿฌํ•œ ๊ตฌ์„ฑ๋œ ์ถœ์ฒ˜์—์„œ ํ˜ธ์ถœํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ฝ˜์†” ์˜ค๋ฅ˜์™€ ํ•จ๊ป˜ ์š”์ฒญ์ด ๊ฑฐ๋ถ€๋ฉ๋‹ˆ๋‹ค.

XMLHttpRequest๋Š” http://localhost :8080/v1/api/search?q=candles๋ฅผ ๋กœ๋“œํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์š”์ฒญํ•œ ๋ฆฌ์†Œ์Šค์— 'Access-Control-Allow-Origin' ํ—ค๋”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ Origin ' http://localhost :9999'๋Š” ์•ก์„ธ์Šค๊ฐ€ ํ—ˆ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋‹น์‹ ์€ ์†๋‹˜ ๋ชฉ๋ก์— ์—†์Šต๋‹ˆ๋‹ค.

๋‚ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ–ˆ์Šต๋‹ˆ๋‹ค.
๋‚ด ํŠน๊ธ‰ API์— ์•ก์„ธ์Šคํ•˜๋ ค๊ณ ํ–ˆ๋‹ค localhost:3000 ์— ๋‚ด VUE ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์—์„œ localhost:8080 ํ•˜์ง€๋งŒ, ์˜ค๋ฅ˜ ๋“ฑ์„ ์–ป๊ณ  ์žˆ์—ˆ๋‹ค.
์ž‘๋™ํ•˜๋ ค๋ฉด http:// ๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
๋”ฐ๋ผ์„œ ๊ฐœ๋ฐœ ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•  ๋•Œ localhost:3000 ๋Œ€์‹  http://localhost:3000 ์‚ฌ์šฉํ•˜์‹ญ์‹œ์˜ค.

Wikmedia API์™€ ๋™์ผํ•œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. CORS ํŽ˜์ด์ง€(https://www.mediawiki.org/wiki/Manual:$wgCrossSiteAJAXdomains)๋ฅผ ์‚ดํŽด๋ณด๊ณ  ์š”์ฒญ์— origin=*์„ ์ถ”๊ฐ€ํ–ˆ๊ณ  ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

axios.get('https://en.wikipedia.org/w/api.php?action=opensearch&format=json&origin=*&search=Albert') .then(function(res) { console.log(res); }) .catch(function(err) { console.log('Error: =>' + err); })

๋ฌด์„œ์šด ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ๋ฐ›์•˜์ง€๋งŒ ๋‚ด ์š”์ฒญ์€ ์„œ๋ฒ„์— ๋„๋‹ฌํ–ˆ์Šต๋‹ˆ๋‹ค.

XMLHttpRequest cannot load "...url here...". No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access.

Axios ํŒ€, ๊ณ ์น  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ???

@mellogarrett ์ด๊ฒƒ์€ https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS

์ค‘์š”ํ•œ ์ธ์šฉ:

"๋ณด์•ˆ์ƒ์˜ ์ด์œ ๋กœ ๋ธŒ๋ผ์šฐ์ €๋Š” ์Šคํฌ๋ฆฝํŠธ ๋‚ด์—์„œ ์‹œ์ž‘๋œ ๊ต์ฐจ ์ถœ์ฒ˜ HTTP ์š”์ฒญ์„ ์ œํ•œํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด XMLHttpRequest ๋ฐ Fetch๋Š” ๋™์ผํ•œ ์ถœ์ฒ˜ ์ •์ฑ…์„ ๋”ฐ๋ฆ…๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ XMLHttpRequest ๋˜๋Š” Fetch๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ์ž์ฒด ๋„๋ฉ”์ธ์— ๋Œ€ํ•ด์„œ๋งŒ HTTP ์š”์ฒญ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ฐœ์„ ํ•˜๊ธฐ ์œ„ํ•ด ๊ฐœ๋ฐœ์ž๋Š” ๋ธŒ๋ผ์šฐ์ € ๊ณต๊ธ‰์—…์ฒด์— ๋„๋ฉ”์ธ ๊ฐ„ ์š”์ฒญ์„ ํ—ˆ์šฉํ•˜๋„๋ก ์š”์ฒญํ–ˆ์Šต๋‹ˆ๋‹ค."

์ด ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” ์‚ฌ๋žŒ๋“ค ์ค‘ ๋Œ€๋ถ€๋ถ„์€ OPTIONS ์š”์ฒญ์— ์‘๋‹ตํ•˜๋Š” ์„œ๋ฒ„๊ฐ€ ์—†์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. OPTIONS ๋ฐ POST ์š”์ฒญ ๋ชจ๋‘์— ๋Œ€ํ•œ ํ•ธ๋“ค๋Ÿฌ(CORS ํ—ค๋” ํฌํ•จ)๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜์‹ญ์‹œ์˜ค. ํด๋ผ์ด์–ธํŠธ(axios)๋Š” ๋จผ์ € OPTIONS๋ฅผ pingํ•œ ๋‹ค์Œ POST๋ฅผ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

Firefox์—์„œ๋Š” ๋™์ผํ•œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜์ง€๋งŒ Chromium์—์„œ๋Š” ๋ฐœ์ƒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ (Firefox์—์„œ) NoScript๊ฐ€ ์›๊ฒฉ ์„œ๋ฒ„์— ๋Œ€ํ•œ ์š”์ฒญ์„ ๋ง‰๋Š” ๊ฒƒ์„ ๊ธฐ์–ตํ–ˆ์Šต๋‹ˆ๋‹ค. NoScript(๋˜๋Š” ์ด์™€ ์œ ์‚ฌํ•œ ํ”Œ๋Ÿฌ๊ทธ์ธ)๊ฐ€ ์„ค์น˜๋˜์–ด ์žˆ๋Š” ๊ฒฝ์šฐ ๋จผ์ € ํ™•์ธํ•˜์‹ญ์‹œ์˜ค.
์ œ ๊ฒฝ์šฐ์—๋Š” ๋ฌธ์ œ๊ฐ€ Axios์™€ ๊ด€๋ จ์ด ์—†์—ˆ์Šต๋‹ˆ๋‹ค. ํ›Œ๋ฅญํ•œ ์ผ์„ ํ•ด์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ์— ๋Œ€ํ•œ ์ˆ˜์ • ํ”„๋กœ๊ทธ๋žจ์„ ๊ฒ€์ƒ‰ํ•˜๋Š” ๋‹ค๋ฅธ ์‚ฌ๋žŒ์˜ ๊ฒฝ์šฐ ๋™์ผํ•œ ์ฆ์ƒ์ด ์žˆ์—ˆ์ง€๋งŒ ์„œ๋ฒ„์˜ php.ini ์„ค์ •์—์„œ ๋ฌธ์ œ๋ฅผ ์ถ”์ ํ–ˆ์Šต๋‹ˆ๋‹ค.

๋‚ด ๋น„ํ–‰ ์ „ OPTIONS ์š”์ฒญ์ด ์„ฑ๊ณตํ–ˆ๊ณ  ์ ์ ˆํ•œ POST ์š”์ฒญ์ด ๋’ค๋”ฐ๋ž์ง€๋งŒ @mellogarrett ๊ณผ ๋น„์Šทํ•œ No 'Access-Control-Allow-Origin' header is present on the requested resource... ๊ณ„์† ๋ฐ›๊ณ  ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค . ์ด๊ฒƒ์€ ์™„์ „ํžˆ ์ด์ƒํ•ด ๋ณด์˜€์œผ๋ฏ€๋กœ Chrome ํ”Œ๋Ÿฌ๊ทธ์ธ ์„ ์‚ฌ์šฉํ•˜์—ฌ CORS ๋ณดํ˜ธ๋ฅผ ์ผ์‹œ์ ์œผ๋กœ ๋น„ํ™œ์„ฑํ™”ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ ํ›„ ๋ฌธ์ œ๊ฐ€ ์‹ค์ œ๋กœ PHP ์˜ค๋ฅ˜๋ผ๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

Deprecated: Automatically populating $HTTP_RAW_POST_DATA is deprecated and will be removed in a future version. To avoid this warning set 'always_populate_raw_post_data' to '-1' in php.ini and use the php://input stream instead. in Unknown on line 0

์ด ๊ฒŒ์‹œ๋ฌผ ์ด ๋ฌธ์ œ์— ๋Œ€ํ•œ ๋” ๋งŽ์€ ์ •๋ณด๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์ง€๋งŒ, ๋‹น์‹ ์€ PHP 5.6์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ์งง์€์—, ๋‹น์‹ ์€ ์ฃผ์„์„ ์ œ๊ฑฐํ•œ๋‹ค always_populate_raw_post_data ๊ท€ํ•˜์˜ php.ini๊ณผ ์„ธํŠธ์— -1 . ๋‹ค๋ฅธ ์‚ฌ๋žŒ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐ ๋ช‡ ์‹œ๊ฐ„์„ ์ ˆ์•ฝํ•  ์ˆ˜ ์žˆ๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค. ๐Ÿค“

์•ˆ๋…•ํ•˜์„ธ์š” @daltonamitchell ๋™์ผํ•œ ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค(์กฐ๊ฑด์— ๋”ฐ๋ฅด๋ฉด ๋™์ผํ•œ ๋ฌธ์ œ์ž„์„ ๋‚˜ํƒ€๋ƒ„). ํ•˜์ง€๋งŒ ๊ถ๊ธˆํ•œ ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์›์‹œ ํฌ์ŠคํŠธ ๋ฐ์ดํ„ฐ ์˜ค๋ฅ˜๊ฐ€ ๋ฌธ์ œ๋ผ๋Š” ๊ฒƒ์„ ์–ด๋–ป๊ฒŒ ์•Œ์•„๋ƒˆ์Šต๋‹ˆ๊นŒ? ํฌ๋กฌ ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์‚ฌ์šฉํ•  ๋•Œ CORS ์š”์ฒญ์ด ์ง„ํ–‰๋˜๊ณ  ๋ชจ๋“  ๊ฒƒ์ด ์ž˜ ์ž‘๋™ํ•œ๋‹ค๊ณ  ์–ธ๊ธ‰ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ํ—ค๋”๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์„ค์ •๋˜์–ด ์žˆ์–ด๋„ ํ”Œ๋Ÿฌ๊ทธ์ธ ์—†์ด๋Š” ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์•„๋งˆ๋„ ์ง€์› ์ค‘๋‹จ ๋ฉ”์‹œ์ง€๊ฐ€ ํ‘œ์‹œ๋˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์ง€๋งŒ ๋ฌธ์ œ๋Š” ์—ฌ์ „ํžˆ ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค...? ๊ทธ๊ฒƒ์„ ํ™•์ธํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์กฐ์–ธ์„ ์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

@RT-TL ํ”Œ๋Ÿฌ๊ทธ์ธ์€ CORS๊ฐ€ ์ฐจ๋‹จํ•˜์ง€ ์•Š๊ณ  ์‘๋‹ต ๋‚ด์šฉ์„ ๋ณด๋Š” ๋ฐ๋งŒ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ์ œ ๊ฒฝ์šฐ์—๋Š” ํ…Œ์ŠคํŠธ ๋ชฉ์ ์œผ๋กœ Hello World ์™€ ๊ฐ™์€ ๋ฌธ์ž์—ด์„ ๋ฐ˜ํ™˜ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— CORS๋ฅผ ๋น„ํ™œ์„ฑํ™”ํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒƒ์„ ๋ณด์•˜์Šต๋‹ˆ๋‹ค.

Deprecated: Automatically populating $HTTP_RAW_POST_DATA is deprecated and will be removed in a future version. To avoid this warning set 'always_populate_raw_post_data' to '-1' in php.ini and use the php://input stream instead. in Unknown on line 0
Hello World

์ปจํŠธ๋กค๋Ÿฌ ๋ฉ”์†Œ๋“œ ์ƒ๋‹จ์— error_reporting(E_ERROR | E_WARNING | E_PARSE | E_NOTICE) ๋˜๋Š” error_reporting(E_ALL) ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ PHP ๊ฒฝ๊ณ ๋ฅผ ํ™œ์„ฑํ™”ํ–ˆ๋Š”์ง€ ํ™•์ธํ•˜์‹ญ์‹œ์˜ค. ์—ฌ์ „ํžˆ ์•„๋ฌด ๊ฒƒ๋„ ํ‘œ์‹œ๋˜์ง€ ์•Š์œผ๋ฉด ๊ฐ„๋‹จํ•œ JSON ์‘๋‹ต์„ ๋ฐ˜ํ™˜ํ•˜์—ฌ ์˜ˆ์ƒ๋Œ€๋กœ ๋ณด์ด๋Š”์ง€ ํ™•์ธํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ๊ฐ€ ๊ณ„์† ๋ฐœ์ƒํ•˜๋Š” ์‚ฌ๋žŒ์ด ์žˆ์Šต๋‹ˆ๊นŒ? ๋‚˜๋Š” ๊ฐ™์€ ๊ฒƒ์„ ์‹คํ–‰ํ•˜๊ณ ์žˆ๋‹ค :

const instance = axios.create({
    baseURL: 'http://localhost/',
    responseType: 'json',
    headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json',
        'Authorization': 'test',
        'X-Test': 'testing'
    }
})
axios.get('v2/portal/bar/foo?')

์‘๋‹ต ํ—ค๋”

HTTP/1.1 401 Unauthorized
Server: nginx/1.11.10
Date: Fri, 24 Mar 2017 07:12:13 GMT
Content-Type: application/json; charset=UTF-8
Content-Length: 0
Connection: keep-alive
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, PUT, DELETE, GET, OPTIONS
Access-Control-Allow-Headers: *

์š”์ฒญ ํ—ค๋”

OPTIONS /v2/portal/bar/foo? HTTP/1.1
Host: localhost
Connection: keep-alive
Access-Control-Request-Method: GET
Origin: http://localhost:3000
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36
Access-Control-Request-Headers: authorization,content-type,x-test
Accept: */*
Referer: http://localhost:3000/dashboard/report
Accept-Encoding: gzip, deflate, sdch, br
Accept-Language: en-US,en;q=0.8,fr;q=0.6,nl;q=0.4,zh-TW;q=0.2,zh;q=0.2,zh-CN;q=0.2

๋‚ด ํ—ค๋”๊ฐ€ ์ œ๋Œ€๋กœ ์ „์†ก๋˜์ง€ ์•Š๋Š” ์ด์œ ๋ฅผ ์•Œ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์—์„œ๋„ ๋™์ผํ•œ ๋ฌธ์ œ๋กœ OPTIONS ์š”์ฒญ์ด ์ˆ˜ํ–‰๋˜์ง€๋งŒ POST ์š”์ฒญ์€ ์ˆ˜ํ–‰๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

TLDR: ๊ฐ€์ ธ์˜ค๊ธฐ๊ฐ€ ์ž‘๋™ํ•˜๊ณ  axios๋Š” JSON.stingify ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ํ•œ ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ OPTIONS๊ฐ€ ๊ต์ฐจ ์ถœ์ฒ˜ ์š”์ฒญ์— ๋Œ€ํ•ด ์„ค์ •๋œ ํ—ค๋”์™€ ํ•จ๊ป˜ 200์„ ๋ฐ˜ํ™˜ํ•˜์ง€๋งŒ POST๋Š” ์ˆ˜ํ–‰๋˜์ง€ ์•Š๋Š” ์ด ์˜ค๋ฅ˜์˜ ๋ณ€ํ˜•๋„ ๋ณด์•˜์Šต๋‹ˆ๋‹ค. ์ด ํ™•์žฅ์„ ์‚ฌ์šฉํ•˜๊ณ  ์˜ˆ์ƒ๋Œ€๋กœ ์ž‘๋™ํ•˜๊ธฐ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์—ฌ๊ธฐ์—๋Š” ์ผ์ข…์˜ ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค๊ณ  ํ™•์‹ ํ•ฉ๋‹ˆ๋‹ค. ๋‚ด ์š”์ฒญ์„ ์‚ดํŽด๋ณด์‹ญ์‹œ์˜ค.

๋‚ด ์„œ๋ฒ„๊ฐ€ Access-Control-Allow-Origin: * ๋กœ ์‘๋‹ตํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
๋‹ค์Œ์€ ์ฝ”๋“œ์™€ ์Šคํฌ๋ฆฐ์ƒท์ด ์žˆ๋Š” ๋ชจ๋“  ์˜ˆ์ž…๋‹ˆ๋‹ค.

์•ก์‹œ์˜ค์Šค:

axios.post('http://localhost:3001/card', { test: 'test' })

axios_cors


์ˆ ์ฑ…:

    return fetch('http://localhost:3001/card', {
      method: 'POST',
      body: { test: 'test' },
    })

fetch_no_stringify

JSON.stringify ์™€ ํ•จ๊ป˜

    return fetch('http://localhost:3001/card', {
      method: 'POST',
      body: JSON.stringify({ test: 'test' }),
    })

fetch_cors

๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋‚ด ๋ฐ์ดํ„ฐ๋ฅผ JSON.stringify ํ•˜์—ฌ axios๊ฐ€ ์ž‘๋™ํ•˜๋„๋ก ํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

    return axios.post('http://localhost:3001/card', JSON.stringify({ test: 'test' }));

axios_json_stringify

@kwhitaker๊ฐ€ ์„ค๋ช…ํ•œ ๊ฒƒ๊ณผ ๋™์ผํ•œ ๋ฌธ์ œ์— ์ง๋ฉดํ–ˆ์Šต๋‹ˆ๋‹ค. @zlyi๊ฐ€ ์ œ์•ˆํ•œ ๋Œ€๋กœ axios.defaults.withCredentials = true; ํ–‰์„ ์ถ”๊ฐ€ํ–ˆ๊ณ  ๋ชจ๋“  ๊ฒƒ์ด ์˜ˆ์ƒ๋Œ€๋กœ ์ž‘๋™ํ•˜๊ธฐ ์‹œ์ž‘ํ–ˆ์Šต๋‹ˆ๋‹ค.

๋ชจ๋“  ๊ฒƒ์„ ์‹œ๋„ํ–ˆ์ง€๋งŒ ์—ฌ์ „ํžˆ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. :(

๋ชจ๋“  ๊ฒƒ์„ ์‹œ๋„ํ–ˆ์ง€๋งŒ ์—ฌ์ „ํžˆ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. :(

.htaccsess์— ๋‹ค์Œ์„ ์ถ”๊ฐ€ํ•˜์—ฌ ๋ฌธ์ œ๋ฅผ ๊ด€๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค.

<IfModule mod_headers.c> 
Header add Access-Control-Allow-Headers "origin, x-requested-with, content-type" 
Header add Access-Control-Allow-Methods "PUT, GET, POST, DELETE, OPTIONS" 
</IfModule>

ํ”„๋ก์‹œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. package.json ํ”„๋ก์‹œ ์ถ”๊ฐ€

{
    "proxy": "http://some-url/some-endpoint"
}

๊ทธ๋Ÿฐ ๋‹ค์Œ ์š”์ฒญ:

axios.get('/user?ID=12345')
  .then(function (response) {
    console.log(response)
  })
  .catch(function (error) {
    console.log(error)
  })

์ด๊ฒƒ์€ ์„œ๋ฒ„ ์ธก ๋ฌธ์ œ์ด๋ฉฐ ์‘๋‹ต ํ—ค๋”์— 'Acces-Control-Allow-Origin': '*' ๊ฐ€ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. Express๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ๋ณด๋‹ค ๊ฐ•๋ ฅํ•˜๊ณ  ์šฐ์•„ํ•œ ๊ตฌํ˜„์„ ์œ„ํ•ด npm-cors ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

+1 @ProfNandaa
๋‚ด ๋กœ์ปฌ ์„œ๋ฒ„์—์„œ ๋‚ด๋ณด๋‚ด๊ธฐ๋ฅผ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.

# cors.js file
module.exports = (req, res, next) => {
  res.setHeader("Access-Control-Allow-Origin", "*");
  res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
  next();
}

๊ทธ๋ž˜์„œ ๋‚˜๋Š” ๋‹ค์Œ์„ ํ• ๋‹นํ•ฉ๋‹ˆ๋‹ค.
```
const cors = ์š”๊ตฌ('cors');
๋ผ์šฐํ„ฐ ์‚ฌ์šฉ(cors);
````
์ด์ œ ๊ณ„์† ... ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค

์„œ๋ฒ„๊ฐ€ OPTION ์š”์ฒญ์„ ์ˆ˜๋ฝํ•˜์ง€ ์•Š์œผ๋ฉด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

"์„œ๋ฒ„์— OPTION ์š”์ฒญ ์ฒ˜๋ฆฌ ์ถ”๊ฐ€"๋ผ๊ณ  ๋งํ•˜๋Š” ์‚ฌ๋žŒ๋“ค์˜ ๊ฒฝ์šฐ ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. OPTION ์š”์ฒญ ์ฒ˜๋ฆฌ๊ฐ€ ํ™œ์„ฑํ™”๋œ ๋กœ์ปฌ ํ™˜๊ฒฝ์„ ์‹คํ–‰ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

Axios.post(url, obj) ๊ฐ€ CORS 403 ๊ธˆ์ง€ ์˜ค๋ฅ˜๋ฅผ ๋ฐ˜ํ™˜ํ–ˆ์ง€๋งŒ Axios.post(url, JSON.stringify(obj)) ์—…๋ฐ์ดํŠธํ•˜๋ฉด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ž‘๋™ํ•˜๋Š” ์œ„์˜ ์‚ฌ์šฉ์ž์™€ ๋™์ผํ•˜๊ฒŒ ์ด ๋ฌธ์ œ๋ฅผ ๊ฒฝํ—˜ํ–ˆ์Šต๋‹ˆ๋‹ค.

์ €๋Š” ๊ฐ„๋‹จํ•œ ํŠœํ† ๋ฆฌ์–ผ ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ ์ค‘์ด๋ฉฐ ๋‹ค์–‘ํ•œ API์— ์•ก์„ธ์Šคํ•˜๋Š” ๋ฐ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ์ฐพ์€ ์œ ์ผํ•œ ์†”๋ฃจ์…˜์€ ์œ„์˜ thiagodebastos๊ฐ€ ์–ธ๊ธ‰ํ•œ ์†”๋ฃจ์…˜์ž…๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋‹จ์ˆœํžˆ get์„ jsonp๋กœ ๋Œ€์ฒดํ–ˆ๊ณ  ๋ฐ์ดํ„ฐ์— ์•ก์„ธ์Šคํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š”์ด ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ๊ณ  koa-cors๋Š” ๊ฐ„๋‹จํ•œ ํ•ด๊ฒฐ์ฑ…์ด์—ˆ์Šต๋‹ˆ๋‹ค! (ProfNandaa์— ๋”ฐ๋ฅธ Express ์‚ฌ์šฉ์ž๋ฅผ ์œ„ํ•œ npm-cors)

์—ฌ์ „ํžˆ ์ด๊ฒƒ์— ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” ์‚ฌ๋žŒ๋“ค์„ ์œ„ํ•ด: Axios๋Š” JSON.encoded ์—†์ด ์š”์ฒญ์˜ ๋ณธ๋ฌธ์œผ๋กœ JSON์„ ์ „์†กํ•˜๊ณ  Axios ๋ฐ ์š”์ฒญ์— ์‘๋‹ตํ•˜๋Š” ์„œ๋ฒ„๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ตฌ์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์‹ค๋ง์Šค๋Ÿฌ์šด ์‹œํ–‰์ฐฉ์˜ค๋ฅผ ๊ฒช์—ˆ์ง€๋งŒ Axios์—์„œ ์ž˜ ์ž‘๋™ํ•˜๋Š” ๋„๋ฉ”์ธ ๊ฐ„ ์š”์ฒญ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

๋ช‡ ๊ฐ€์ง€ ์‚ฌํ•ญ:

์š”์ฒญ์ด ์ž‘๋™ํ•˜๋ ค๋ฉด ๋‹ค์Œ์„ ํ™•์ธํ•˜์‹ญ์‹œ์˜ค.

  • ์„œ๋ฒ„๋Š” ๋ชจ๋“  ์˜ฌ๋ฐ”๋ฅธ ํ—ค๋”๊ฐ€ ์„ค์ •๋œ 200 ์ด์™ธ์˜ ๋‹ค๋ฅธ ์‘๋‹ต์ธ ๊ฒƒ์ฒ˜๋Ÿผ OPTIONS ์š”์ฒญ์— ์‘๋‹ตํ•˜๋ฉฐ "preflighted" ์š”์ฒญ ์€ ์‹คํŒจํ•ฉ๋‹ˆ๋‹ค.

  • ์š”์ฒญ์€ ์˜ฌ๋ฐ”๋ฅธ ํ—ค๋”๋กœ ์ด๋ฃจ์–ด์ง€๋ฉฐ ์„œ๋ฒ„๋Š” ํ•„์š”ํ•œ ๋ชจ๋“  ํ—ค๋”๋กœ ์‘๋‹ตํ•ฉ๋‹ˆ๋‹ค.

  • ์ฟ ํ‚ค/์ธ์ฆ ํ—ค๋” ๋˜๋Š” TLS ํด๋ผ์ด์–ธํŠธ ์ธ์ฆ์„œ๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ Axios ์š”์ฒญ์— ๋Œ€ํ•ด allowCredentials๋ฅผ true๋กœ ๋ณด๋ƒ…๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๊ธฐ๋ณธ( axios.defaults.withCredentials = true ) ๋˜๋Š” ์š”์ฒญ๋ณ„๋กœ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์„ฑ๊ณตํ•œ ์š”์ฒญ ํ—ค๋”์˜ ์˜ˆ

Access-Control-Request-Headers: Content-Type
Access-Control-Request-Method: GET

์„ฑ๊ณตํ•œ ์‘๋‹ต ํ—ค๋”์˜ ์˜ˆ

Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS
Access-Control-Allow-Origin: http://your-origin-url.com

์šฐ๋ฆฌ๋Š” ์ ์ฐจ์ ์œผ๋กœ ์‘๋‹ต ํ—ค๋”๋ฅผ ์ถ”๊ฐ€ํ–ˆ๊ณ  ๋‹ค์–‘ํ•œ ์กฐํ•ฉ์œผ๋กœ ์ง„๋‹จํ•˜๊ธฐ ์–ด๋ ค์šด ์˜ค๋ฅ˜์™€ ์˜ˆ๊ธฐ์น˜ ์•Š์€ ๋™์ž‘์ด ์žˆ์Œ์„ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค.

Access-Control-Allow-Credentials: true ๊ฐ€ ์—†์œผ๋ฉด ์ฟ ํ‚ค๊ฐ€ ์ „์†ก๋˜๊ฑฐ๋‚˜ ์ง€์†๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๋Š” ํ•ด๋‹น ํ—ค๋”์— ๋Œ€ํ•œ MDN ํŽ˜์ด์ง€๋ฅผ ์ฝ์€ ํ›„ ์˜๋ฏธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ๋ฌธ์„œ๋ฅผ ์ฝ์œผ๋ฉด ๋„์›€

๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” ์‚ฌ๋žŒ์€ ๋ˆ„๊ตฌ์—๊ฒŒ๋‚˜ ...Allow-Headers: Content-Type ๊ฐ€ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

Access-Control-Allow-Origin: '*'
Access-Control-Allow-Methods: ...
Access-Control-Allow-Headers: Content-Type, Accept

'Allow-Control-Allow-Origin: *'์ด๋ผ๋Š” ํฌ๋กฌ ํ™•์žฅ ํ”„๋กœ๊ทธ๋žจ์„ ์‚ฌ์šฉ ์ค‘์ž…๋‹ˆ๋‹ค.
๊ทธ๊ฒƒ์ด ur ๋ฌธ์ œ๋ฅผ ๋„์šธ ์ˆ˜ ์žˆ๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค.
2017-07-19 14 06 37

Axios๊ฐ€ ์ด ์˜ค๋ฅ˜๋ฅผ ์ˆ˜์ •ํ•  ์ˆ˜ ์—†๋Š” ์ด์œ ๋ฅผ ์ดํ•ดํ•˜์ง€ ๋ชปํ•˜๋Š” ์‚ฌ๋žŒ์„ ์œ„ํ•ด:

์ด๊ฒƒ์€ Axios ๋ฌธ์ œ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. ๋ธŒ๋ผ์šฐ์ € ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค. ๋ธŒ๋ผ์šฐ์ €์˜ JS๋Š” ์ ์ ˆํ•œ ํ—ค๋”๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์€ ์„œ๋ฒ„์— ๋Œ€ํ•œ ์š”์ฒญ์„ ๊ฑฐ๋ถ€ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์„ ํด๋ผ์ด์–ธํŠธ์—์„œ React์™€ ๊ฐ™์€ ๊ฒƒ๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ํ˜ผ๋™ํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค. ์ด๊ฒƒ์€ React ๋˜๋Š” Axios ๋ฌธ์ œ๊ฐ€ ์•„๋‹ˆ๋ฉฐ ๋‹จ์ˆœํžˆ CORS ํ‘œ์ค€์„ ์ค€์ˆ˜ํ•˜๋Š” ๋ธŒ๋ผ์šฐ์ €์ž…๋‹ˆ๋‹ค.

JakeElder๋Š” https://github.com/mzabriskie/axios/issues/191#issuecomment -311069164์—์„œ API์˜ ์„œ๋ฒ„ ์ธก์—์„œ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•˜๋Š” ์ž‘์—…์— ๋Œ€ํ•œ ์ข‹์€ ์„ค๋ช…์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์•ก์„ธ์Šคํ•˜๋ ค๋Š” ์„œ๋ฒ„๋ฅผ ์ œ์–ดํ•  ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ ํ”„๋ก์‹œ ์„œ๋ฒ„๋ฅผ ๋งŒ๋“ค์–ด ์ฝ˜ํ…์ธ ๋ฅผ ๊ฐ€์ ธ์™€ ์˜ฌ๋ฐ”๋ฅธ ํ—ค๋”์™€ ํ•จ๊ป˜ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์ด ๊ตฌํ˜„๋œ ์ด์œ ๋Š” ํ™•์‹คํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ •๋ณด๋ฅผ ์–ป๊ธฐ ์œ„ํ•ด ์„œ๋ฒ„์— ์š”์ฒญ์„ ํ•˜๊ณ  ์‹ถ์ง€๋งŒ ์„œ๋ฒ„์— ํŠน์ • ํ—ค๋” ์„ธํŠธ๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— ํ•  ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ ํ™•์‹คํžˆ ์งœ์ฆ๋‚ฉ๋‹ˆ๋‹ค. ๋งค์šฐ ์ œํ•œ์ ์ธ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์•„ ๊ธ€์Ž„ ...

@robins-eldo ๋‹ค์‹œ ๋งํ•˜์ง€๋งŒ, ๋‚˜๋Š” ๋‹น์‹ ์ด ์˜ณ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋‚ด ์›๋ž˜ ์˜๊ฒฌ:

For those commenting saying "Add OPTION request handling to your server", that does not work. I'm running a local environment that has OPTION request handling enabled.

I experienced this issue identically as a user above, where Axios.post(url, obj) returned the CORS 403 forbidden error, but updating that to Axios.post(url, JSON.stringify(obj)) worked correctly.

์‹ค์ œ๋กœ Axios ๋ฌธ์ œ๊ฐ€ ์•„๋‹ˆ๋ผ ์„œ๋ฒ„ ๋ฌธ์ œ์˜€๋‹ค๋ฉด OPTIONS ์š”์ฒญ์ด ์–ด๋Š ์ชฝ์ด๋“  ์‹คํŒจํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ์ฒด๋ฅผ ๋ฌธ์ž์—ดํ™”ํ•ด๋„ ์•„๋ฌด๋Ÿฐ ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š์•˜์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@alexanderbanks

OPTION HTTP ๋ฉ”์„œ๋“œ์— ๋Œ€ํ•ด์„œ๋Š” ํ™•์‹คํ•˜์ง€ ์•Š์ง€๋งŒ ๋‚ด ํŠน์ • ๋ฌธ์ œ๋Š” ๋‚ด๊ฐ€ ์ž‘์„ฑํ•œ ๋‚ด๋ถ€ API(๋‚ด๋ถ€ API๋Š” ์—ฌ๊ธฐ์—์„œ ์„œ๋ฒ„์ž„)์— POST๋ฅผ ์‹œ๋„ํ•˜๋Š” React ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด ์˜ค๋ฅ˜๊ฐ€ ๊ณ„์† ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค: Failed to load resource: Origin http://localhost:7149 is not allowed by Access-Control-Allow-Origin. XMLHttpRequest cannot load http://localhost:8902/user-login due to access control checks.

Axios ๋ฌธ์ œ์ผ ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์—ฌ ๋Œ€์‹  Unirest๋ฅผ ์‹œ๋„ํ–ˆ์ง€๋งŒ ๋™์ผํ•œ ์˜ค๋ฅ˜๊ฐ€ ๊ณ„์† ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๋‚˜๋Š” ๊ทธ๊ฒƒ์ด ๋‹ค๋ฅธ ๊ฒƒ์ด์–ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ๋ธŒ๋ผ์šฐ์ € ๋ฌธ์ œ์ธ์ง€ React์ธ์ง€ ํ™•์‹คํ•˜์ง€ ์•Š์ง€๋งŒ API ์„œ๋ฒ„(Nodejs + Express API)์— ๋‹ค์Œ์„ ์ถ”๊ฐ€ํ•˜์ž๋งˆ์ž ๋ชจ๋“  ๊ฒƒ์ด ํด๋ผ์ด์–ธํŠธ ์ธก์—์„œ Axios์™€ Unirest ๋ชจ๋‘์—์„œ ์ž‘๋™ํ•˜๊ธฐ ์‹œ์ž‘ํ–ˆ์Šต๋‹ˆ๋‹ค.

app.use(function(req, res, next) { res.header("Access-Control-Allow-Origin", "*"); next(); });

์•„๋งˆ๋„ ์ด ์žฅ๋ฉด ๋’ค์—์„œ ์‹ค์ œ๋กœ ์ผ์–ด๋‚˜๋Š” ์ผ์— ๋Œ€ํ•œ ๋‚˜์˜ ์ดํ•ด๋Š” ๋‹ค์†Œ ์ œํ•œ์ ์ผ ์ˆ˜ ์žˆ์ง€๋งŒ, ์„œ๋ฒ„์˜ ์ด ์•ฝ๊ฐ„์˜ ์ฝ”๋“œ๋Š” ๋‚˜๋ฅผ ์œ„ํ•ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ–ˆ์Šต๋‹ˆ๋‹ค.

์„œ๋ฒ„๊ฐ€ ์›๋ณธ ์•ก์„ธ์Šค๋ฅผ ๋„ˆ๋ฌด ๋งŽ์ด ์ œํ•œํ•˜์ง€ ์•Š๋Š”์ง€ ํ™•์ธํ•˜๊ณ  no-cor๋ฅผ ํ”ผํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ๋‹ค์Œ์„ ์‹œ๋„ํ•˜์‹ญ์‹œ์˜ค.

    return axios(url, {
      method: 'POST',
      mode: 'no-cors',
      headers: {
        Accept: 'application/json',
        'Content-Type': 'application/json',
      },
      withCredentials: true,
      credentials: 'same-origin',
    }).then(response => {
    })

CORS๊ฐ€ ์ž‘๋™ํ•˜๋Š” ๋ฐฉ์‹์— ๋Œ€ํ•ด ํ˜ผ๋ž€์Šค๋Ÿฌ์›Œํ•˜๋Š” ์‚ฌ๋žŒ๋“ค์ด ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์›๋ž˜ ๋ฌธ์ œ๋Š” CORS์— ๋Œ€ํ•œ ๊ฒƒ์ด ์•„๋‹ˆ์—ˆ์œผ๋ฉฐ ์ตœ์†Œํ•œ ์ค‘์š”ํ•œ ๋ฌธ์ œ์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋‚ด ๋ง์€, CORS๋ฅผ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ตฌ์„ฑํ–ˆ์ง€๋งŒ Post๊ฐ€ ์ž‘๋™ํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ ์„œ๋ฒ„๋ฅผ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ตฌ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์•„๋‹ˆ๋ผ ๋ณด๊ณ ํ•ด์•ผ ํ•  ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค.

API๊ฐ€ ์ด์ƒํ•˜๊ฒŒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋“  cors GET ์š”์ฒญ์ด "credentials : true"๋กœ ์ž‘๋™ํ–ˆ์Šต๋‹ˆ๋‹ค.
POST ์š”์ฒญ์˜ ๊ฒฝ์šฐ ๋™์ผํ•œ ์›๋ณธ ์š”์ฒญ์ด ๋ฐ์ดํ„ฐ ๊ฐœ์ฒด๋ฅผ ๋ฌธ์ž์—ดํ™”ํ•˜์ง€ ์•Š๊ณ  ์ž‘๋™ํ•˜๋Š” ๋ฐ˜๋ฉด CORS POST ์š”์ฒญ์˜ ๊ฒฝ์šฐ ๋ฐ์ดํ„ฐ ๊ฐœ์ฒด๋ฅผ ๋ฌธ์ž์—ดํ™”ํ•  ๋•Œ ์ž‘์—…์ด ์‹œ์ž‘๋ฉ๋‹ˆ๋‹ค.

์ •ํ™•ํ•œ ์ด์œ ๋ฅผ ์–ป์ง€ ๋ชปํ–ˆ์ง€๋งŒ ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์ฃ„์†กํ•˜์ง€๋งŒ ๊ฐ™์€ ์ฃผ์ œ์— ๋Œ€ํ•ด ์„œํด์„ ํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ ๊ฐ™์•„์„œ ์ด ์Šค๋ ˆ๋“œ๋ฅผ ์ž ๊ทธ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ๋ฌธ์ œ์—์„œ ๋‹ค๋ฃจ์ง€ ์•Š์€ ํŠน์ • ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ(์ž˜๋ชป๋œ ๊ตฌ์„ฑ์œผ๋กœ ์ธํ•œ ์ผ๋ฐ˜์ ์ธ CORS ๋ฌธ์ œ, ์–‘์‹ Urlencoded ๋Œ€์‹  JSON์œผ๋กœ ์ „์†ก๋˜๋Š” POST ์š”์ฒญ ๋“ฑ) ํŠน์ • ์„ธ๋ถ€ ์ •๋ณด๊ฐ€ ํฌํ•จ๋œ ์ƒˆ ๋ฌธ์ œ๋ฅผ ์—ฌ์‹ญ์‹œ์˜ค.

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰