์๋ ํ์ธ์,
ํ๋ฅญํ ์ผ์ ํด์ฃผ์
์ ๊ฐ์ฌํฉ๋๋ค.
์ฌ์ดํธ ๊ฐ ์์ฒญ์ ๋์์ผ๋ก ํ๋ ์ผ๋ถ ๋ฆด๋ฆฌ์ค์์ง๋ง ์ฌ์ ํ ์๋ํ์ง ์์ต๋๋ค. ๋๋ ์ด์ ๊ฒ์๋ฌผ์ ํ๊ณ ๋ค์์ ์ถ๊ฐํ๋ ค๊ณ ์๋ํ์ต๋๋ค.
๊ตฌ์ฑ์. ๊ทธ๋ฆฌ๊ณ ๊ทธ๋ค ์ค ๋๊ตฌ๋ ์ผํ์ง ์์์ต๋๋ค. (์ด ๊ธฐ๋ฅ์ ์ค์ ๋ก ์ฌ์ฉํ ์ ์๋ ๊ฒฝ์ฐ ์ถ๊ฐ ์ ๋ณด๋ฅผ ์ ๋ฐ์ดํธํ๋ฉด ๋์์ด ๋ฉ๋๋ค.)
์ต๋ํ ๋นจ๋ฆฌ ์กฐ์ธ ๋ถํ๋๋ฆฝ๋๋ค. ๊ฐ์ฌํฉ๋๋ค.
๋ํ ๊ตฌ์ฑ์์ 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์์ ์ฌ์ดํธ ๊ฐ ์์ฒญ์ ๋ง๋ค์ด ์ฌํํ ์ ์์ต๋๋ค.
๋ด ํ๊ฒฝ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
๋์ผํ ์์ฒญ์ด curl์์๋ ์๋ํ๋ค๋ ์ ์ ์ ์ํ์ญ์์ค.
์กฐ์ฌํด ์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค!
CORS๋ฅผ ์ฌ์ฉํ๋ฉด ์์ฒญ์ด ํ์ฉ๋๋์ง ํ์ธํ๊ธฐ ์ํด ์๋ฒ์ ์คํ ์ ์์ฒญ์ด ์ด๋ฃจ์ด์ง๋๋ค. ๋ชจ๋ ์ถ์ฒ์ ์์ฒญ์ ํ์ฉํ๋ Acces-Control-Allow-Origin: *
ํค๋๋ฅผ ์ค์ ํ์ฌ ์์ฒญ ๋ฐฉ๋ฒ์ผ๋ก OPTIONS
๊ฐ ์๋ ์์ฒญ์ ์๋ฒ๊ฐ ์๋ตํ๋๋ก ํด์ผ ํฉ๋๋ค. ๋๋ ํน์ ์ถ์ฒ Acces-Control-Allow-Origin: http://example.com
๋ง ํ์ฉํ ์ ์์ต๋๋ค.
๋ค, ์ดํดํฉ๋๋ค. ํ์ง๋ง ์๋ฒ๋ ๋ด ๊ฒ์ด ์๋๋๋ค. Baas(backend-as-a-service)๋ฅผ ์ฌ์ฉํ๊ณ ์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ๊ทธ๋ค์ ์ด๋ฏธ ๋ด ๋๋ฉ์ธ์ ํ์ฉ ๋ชฉ๋ก์ ์ถ๊ฐํ์ต๋๋ค. Baas๋ฅผ ์ฌ์ฉํ๋ ๋ค๋ฅธ ์ฌ๋๋ค์ ๊ทธ๋ฐ ๋ฌธ์ ๊ฐ ์์๋์ง ํ์ธํ์ต๋๋ค.
๋๋ ๋น์ ์ด ์ ๊ณตํ ์ค๋ฅ ๋ฉ์์ง๋ฅผ ๋ฌด์ํ ๊ฒ์ด์ง๋ง, ๊ทธ๊ฒ์ ๋ฐ๋ฅด๋ฉด ๋น์ ์ด baas๊ฐ ๋น์ ์ ์ํด ์ผํ๊ณ ์๋ ๊ฒ์ฒ๋ผ ๋ค๋ฆฌ์ง ์์ต๋๋ค. ๊ต์ฐจ ์ถ์ฒ ๋ณด์์ ๋ธ๋ผ์ฐ์ ๋ด์ ์ ํ ์ฌํญ์ผ ๋ฟ์ด๋ฏ๋ก curl์ ์ฌ์ฉํ๋ฉด ์คํจํ์ง ์์ต๋๋ค.
๋ธ๋ผ์ฐ์ ์์ ๋คํธ์ํฌ ํญ์ ์ด๊ณ OPTIONS ์์ฒญ์ ๋ํ ์๋ต์ผ๋ก ์ป์ ๊ฒ์ ๊ณต์ ํ ์ ์์ต๋๊น? ์๋ต ๋ฐ์ดํฐ์ ํค๋๋ฅผ ๋ณด๋ ๊ฒ์ด ์ด ๋ฌธ์ ๋ฅผ ๋๋ฒ๊ทธํ๋ ๋ฐ ๋์์ด ๋๊ธฐ๋ฅผ ๋ฐ๋๋๋ค.
๊ฐ์ฌ ํด์
ํค๋๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
๋ค์์ axios๋ฅผ ์ฌ์ฉํ์ฌ API์์ ๋ด ์ฌ์ฉ์ ํ๋กํ์ ๊ฐ์ ธ์ฌ ๋ GitHub์ ์๋ต ํค๋์ ๋๋ค.
GitHub์์ Access-Control-Allow-Origin: *
์ถ๊ฐํ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค. Baas์ ์๋ต์ Access-Control
์ ํ ํค๋๊ฐ ์์ต๋๋ค.
์๊ฒ ์ต๋๋ค ํ . ๋ต๋ณ์ด ์์ฒญ๋๊ฒ ๋ฆ์ด ์ฃ์กํฉ๋๋ค. ์ด์ ๋ํด ์กฐ๊ธ ๋ ์ดํด๋ณด๊ฒ ์ต๋๋ค. ๋งค์ฐ ๊ฐ์ฌํฉ๋๋ค.
๋ด๊ฐ๋ณด๊ณ ์๋ ๊ฒ์ด ๊ด๋ จ์ด ์๋์ง ์ฌ๋ถ๋ ํ์คํ์ง ์์ต๋๋ค. ๊ธฐ๋ณธ์ ์ผ๋ก ์๊ฒฉ ์๋ฒ์ ์ธ์ฆ ์์ฒญ์ ๋ณด๋ด๊ณ ์ฟ ํค๋ฅผ ๋ค์ ๋ฐ์ ์ ์์ง๋ง ์๋ฒ์ ๋ํ ํ์ ํธ์ถ์ ์ฟ ํค์ ํจ๊ป ์ฟ ํค๋ฅผ ๋ณด๋ด์ง _์์ผ๋ฏ๋ก_ ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค.
๋ค์์ ๋ก๊ทธ์ธ์ ์ํ POST
ํธ์ถ์ ํค๋์
๋๋ค.
๊ทธ๋ฆฌ๊ณ ์ด์ ํ์ GET
ํธ์ถ:
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' })
์ ์ฑ :
return fetch('http://localhost:3001/card', {
method: 'POST',
body: { test: 'test' },
})
JSON.stringify
์ ํจ๊ป
return fetch('http://localhost:3001/card', {
method: 'POST',
body: JSON.stringify({ test: 'test' }),
})
๋ค์๊ณผ ๊ฐ์ด ๋ด ๋ฐ์ดํฐ๋ฅผ JSON.stringify
ํ์ฌ axios๊ฐ ์๋ํ๋๋ก ํ ์ ์์์ต๋๋ค.
return axios.post('http://localhost:3001/card', JSON.stringify({ test: 'test' }));
@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 ๋ฌธ์ ๋ฅผ ๋์ธ ์ ์๊ธฐ๋ฅผ ๋ฐ๋๋๋ค.
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 ์์ฒญ ๋ฑ) ํน์ ์ธ๋ถ ์ ๋ณด๊ฐ ํฌํจ๋ ์ ๋ฌธ์ ๋ฅผ ์ฌ์ญ์์ค.
๊ฐ์ฅ ์ ์ฉํ ๋๊ธ
์ด๋ป๊ฒ ๊ทธ๋ฐ ๊ฑฐ๋ํ ๋ฌธ์ ๊ฐ ํด๊ฒฐ๋์ง ์์ต๋๊น?