\r\n\r\n\r\n```\r\nVies.py\r\n```\r\ndef check(request):\r\n if request.method == \"GET\":\r\n print('ok')\r\n return redirect(\"polls:index\")\r\n json_dict = json.loads(request.body)\r\n\r\n print(json_dict)\r\n \r\n json_str = json.dumps(json_dict, ensure_ascii=False, indent=2)\r\n return HttpResponse(json_str)\r\n```\r\n\r\n### 試したこと\r\n\r\nDjango側では、[こちら](https://murabo.hatenablog.com/entry/2018/02/01/121925)や[こちら](https://teratail.com/questions/172567)のサイトを参考に、```pip install django-cors-headers```を行いsettings.pyを以下の部分を追記しました。\r\n```\r\nINSTALLED_APPS = [\r\n 'corsheaders',\r\n]\r\nMIDDLEWARE = [\r\n 'corsheaders.middleware.CorsMiddleware',\r\n 'django.middleware.common.CommonMiddleware',\r\n]\r\nCORS_ORIGIN_WHITELIST = (\r\n 'http://localhost:8080',\r\n 'http://127.0.0.1:8080',\r\n 'http://127.0.0.1:8000',\r\n)\r\nCORS_ALLOW_CREDENTIALS = True\r\nCORS_ALLOW_CREDENTIALS = True\r\n```\r\nまた、```App.vue```ファイルの以下hedder部分を削除した状態で、postすると```POST http://127.0.0.1:8000/polls/check/ 403 (Forbidden)```とエラーが発生してしまっている状況です。\r\n```\r\n {\r\n headers: {\r\n \"Access-Control-Allow-Origin\": \"*\",\r\n \"Access-Control-Allow-Methods\": \"GET, POST, PATCH, PUT, DELETE, OPTIONS\",\r\n \"Access-Control-Allow-Headers\": \"Origin, Content-Type, X-Auth-Token\"\r\n }\r\n },\r\n```\r\n### 補足情報(FW/ツールのバージョンなど)\r\nエディター:VScode,OS:Mac OS\r\n\r\nどなたか、エラー解決の為、アドバイス頂けましたら幸いです。\r\n\r\n### 追記\r\n[Qiita](https://qiita.com/att55/items/2154a8aad8bf1409db2b)記事を参考に、axiosに```withCredentials: true```を追記しましたが```POST http://127.0.0.1:8000/polls/check/ 403 (Forbidden)```が表示されている状態です。\r\n```\r\n axios.post(\r\n 'http://127.0.0.1:8000/polls/check/',\r\n {\r\n name:this.name,\r\n comment:this.comment\r\n },\r\n { \r\n withCredentials: true\r\n },\r\n \r\n )\r\n```\r\n### 追記2\r\n[こちら](https://manikos.github.io/django-axios-and-csrf-token)の記事を参考に以下の部分をApp.vueに追記しましたが、エラーは解決されていない状況です。\r\n```\r\nimport axios from 'axios';\r\nconst headers = {\"X-CSRFTOKEN\": \"\"}\r\n```\r\naxios.postメソッドには、``` {headers: headers},```を引数に追加しました","answerCount":2,"upvoteCount":0,"datePublished":"2020-07-18T02:22:22.653Z","dateModified":"2020-07-18T04:17:07.781Z","acceptedAnswer":{"@type":"Answer","text":"追記:[Vue 公式ドキュメント](https://cli.vuejs.org/config/#devserver-proxy)によって、フロントエンドとバックエンドのサーバーが同一ではない場合、設定の devServer.proxy にバックエンドサーバーのアドレスを入れれば、フロントエンドで知らないリクエストを全部バックエンドに渡せます。\r\n\r\n```javascript\r\n// vue.config.js\r\nmodule.exports = {\r\n devServer: {\r\n proxy: 'http://localhost:8000'\r\n }\r\n}\r\n```\r\n\r\nそうしたら、リクエストの際にアドレスを明言する必要がなくなります。\r\n\r\n```javascript\r\n axios.post(\r\n '/polls/check/',\r\n {\r\n name:this.name,\r\n comment:this.comment\r\n },\r\n )\r\n```\r\n\r\n追記:そうしてもCSRFを踏んだら、Django側その関数に @csrf_exempt でマークしてください\r\n\r\n```python\r\n@csrf_exempt\r\ndef check():\r\n pass\r\n```\r\n\r\n---\r\n\r\nAkitoshiManabeさんの言う通り、`http://127.0.0.1:8080` と `http://localhost:8080`との違いで Cross Origin エラーが出てます。\r\n\r\nこちらのコードから推測できる誤解を解けておきましょう:\r\n\r\n```javascript\r\n axios.post(\r\n 'http://127.0.0.1:8000/polls/check/',\r\n {\r\n name:this.name,\r\n comment:this.comment\r\n },\r\n {\r\n headers: {\r\n \"Access-Control-Allow-Origin\": \"*\",\r\n \"Access-Control-Allow-Methods\": \"GET, POST, PATCH, PUT, DELETE, OPTIONS\",\r\n \"Access-Control-Allow-Headers\": \"Origin, Content-Type, X-Auth-Token\"\r\n }\r\n },\r\n )\r\n```\r\n\r\n上記の axios の headers はクライアントからサーバーへのリクエストの headers です。例えば、Cookie や Accept など、クライアントができることを示すためです。\r\n\r\nAccess-Control-Allow-Origin、Access-Control-Allow-Methods、Access-Control-Allow-Headers、この三つの headers はサーバーができることですから、サーバーからクライアントへのレスポンスについてるものです。この三つの headers は axios の headers に入れても意味がありません。削除していいです。\r\n\r\n```python\r\nCORS_ORIGIN_WHITELIST = (\r\n 'http://localhost:8080',\r\n 'http://127.0.0.1:8080',\r\n 'http://127.0.0.1:8000',\r\n)\r\n```\r\n\r\n上記の設定をしたら、上記の headers は Django からのレスポンスに CorsMiddleware によって自動的についてるはずですが、カッコを使ってしまい list ではなく tuple を使っていますので、どんな反応してるかわかりません。カッコ () をブラケット [] で書き換えてみたらいかがでしょうか?","dateModified":"2020-07-23T09:41:47.151Z","datePublished":"2020-07-21T10:37:01.978Z","upvoteCount":2,"url":"https://teratail.com/questions/278604#reply-397700"},"suggestedAnswer":[{"@type":"Answer","text":"[オリジン](https://www.ipa.go.jp/security/rfc/RFC6454JA.html) は 「**プロトコル** + ``//`` + **ホスト名** + **ポート番号**」で成る文字列です。\r\n\r\nブラウザは ``http://127.0.0.1:8080`` と ``http://localhost:8080`` とはクロスオリジンの関係にあるものとして、CORS エラーを吐きます。\r\n\r\n> エラー解決の為、アドバイス頂けましたら幸いです\r\n\r\n他者の記事やコードを真似て、手を動かして確認できているように感じますが、\r\nそれぞれの仕組み(なぜ、そのように書けるのか?)について、詳細を再確認してください\r\n\r\n* MDN [HTTPヘッダ](https://developer.mozilla.org/ja/docs/Web/HTTP/Headers) ... 要求ヘッダ / 応答ヘッダ の違いを間違えない\r\n* MDN [オリジン間リソース共有 (CORS)](https://developer.mozilla.org/ja/docs/Web/HTTP/CORS)\r\n* Google検索 [CSRF](https://www.google.co.jp/search?q=CSRF) ... (ご質問の追記2に関連)CORSを解決して考えましょう。\r\n\r\n活字ばかりだと退屈かもしれませんが、**仕組みを覚える**と、エラー原因は自身で特定できるようになります。","dateModified":"2020-07-18T06:29:23.336Z","datePublished":"2020-07-18T06:29:23.336Z","upvoteCount":1,"url":"https://teratail.com/questions/278604#reply-396778","comment":[{"@type":"Comment","text":"ご回答ありがとうございます。\r\n>MDN HTTPヘッダ ... 要求ヘッダ / 応答ヘッダ の違いを間違えない\r\nMDN オリジン間リソース共有 (CORS)\r\nGoogle検索 CSRF ... (ご質問の追記2に関連)CORSを解決して考えましょう。\r\n\r\nこちら、確認してみました。\r\nやはり恐らく、csrfトークンをpostをする際に、必要だということが分かったのですが、csrfトークンの生成&付加の方法が分からず、手詰まりしてしまってる状況です。。","datePublished":"2020-07-18T07:59:54.511Z","dateModified":"2020-07-18T07:59:54.511Z"},{"@type":"Comment","text":"CSRFの特徴は、\r\n1. サーバー-ブラウザ間で事前にトークン(合言葉)を示し合わせる。\r\n2. POSTされたら、トークンを照合してDBに書き込み/無視。トークンを棄てる\r\n\r\n本題(CORS)に関連するのは、1. でトークンを示し合わせる際に HTTPヘッダーを使う場合(Access-Control-Allow-Headers が必要)です。他にも単に input[type=hidden] に埋め込む実装もあります(CORSは無関係)。\r\n修学目的であれば、複数の決め打ちされたトークンをループする手法が使えるでしょう。\r\n詳細はご質問(CORS)とは別になりますので、概要のみのコメントとさせていただきます。","datePublished":"2020-07-18T08:46:47.428Z","dateModified":"2020-07-18T08:46:47.428Z"},{"@type":"Comment","text":"ご返信ありがとうございます。\r\n> 1. サーバー-ブラウザ間で事前にトークン(合言葉)を示し合わせる。\r\nこちらなのですが、実際に運用していく目的であります為、ランダムに一意に生成されるトークンの生成を考えています。\r\nまた、サーバーとブラウザ間で示し合せる為には、フロント側で生成したcsrfトークンをDjango側で検証する必要かと思うのですが、今回djangoのテンプレートエンジンを使用し{% csrf_token %}のような形で生成している訳ではない為、実際にどのようにブラウザから送られてきたトークンを検証するのかといった部分が分からない状態ですね。。","datePublished":"2020-07-18T10:01:16.347Z","dateModified":"2020-07-18T10:02:37.665Z"},{"@type":"Comment","text":"> ブラウザから送られてきたトークンを検証する\r\nサーバー側で生成してブラウザに渡した情報ですので、セッションとしてサーバー側で保持しておく。\r\nPOST時にデータ保存前に比較する(比較後はセッションとの紐付けを解除)。という形で検証できそうですよね。\r\n\r\nご質問の本題であるCORSから脱線して、CSRF、Sessionの話題に変わっていますので、色々と試してみて、改めて質問にまとめてみてはいかがでしょう。","datePublished":"2020-07-18T10:26:42.958Z","dateModified":"2020-07-18T10:26:42.958Z"},{"@type":"Comment","text":"そうですね。もう少し色々と調べてみて、新たに回答がつかなかった場合、質問を新たに立てるか考えたいと思います。","datePublished":"2020-07-18T16:21:42.572Z","dateModified":"2020-07-18T16:22:11.361Z"}]}],"breadcrumb":{"@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"トップ","url":"https://teratail.com"},{"@type":"ListItem","position":2,"name":"Vue.jsに関する質問","url":"https://teratail.com/tags/Vue.js"},{"@type":"ListItem","position":3,"name":"Vue.js","url":"https://teratail.com/tags/Vue.js"}]}}}
前提・実現したいこと
axiosを用いて、ajax通信を行いたいです。
発生している問題・エラーメッセージ
デベロッパーツールのコンソールに以下のようなエラーが発生してしまいました。
Access to XMLHttpRequest at 'http://127.0.0.1:8000/polls/check/' from origin 'http://localhost:8080' has been blocked by CORS policy: Request header field access-control-allow-origin is not allowed by Access-Control-Allow-Headers in preflight response.
該当のソースコード
App.Vue
<template>
<div id="app">
<h3>掲示板に投稿する</h3>
<label for="name">ニックネーム:</label>
<input id="name" type="text" v-model="name">
<br>
<label for="comment">コメント:</label>
<textarea id="comment" v-model="comment"></textarea>
<br>
<button @click="createComment">コメントをサーバーに送る</button>
<h2>掲示板</h2>
</div>
</template>
<script>
import axios from 'axios';
export default {
data(){
return{
name:'',
comment:'',
};
},
methods: {
createComment(){
axios.post(
'http://127.0.0.1:8000/polls/check/',
{
name:this.name,
comment:this.comment
},
{
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, PATCH, PUT, DELETE, OPTIONS",
"Access-Control-Allow-Headers": "Origin, Content-Type, X-Auth-Token"
}
},
)
.then(response => {
console.log(response);
})
.catch(error => {
console.log(error);
})
console.log('hello')
this.name = '';
this.comment = '';
}
},
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
Vies.py
def check(request):
if request.method == "GET":
print('ok')
return redirect("polls:index")
json_dict = json.loads(request.body)
print(json_dict)
json_str = json.dumps(json_dict, ensure_ascii=False, indent=2)
return HttpResponse(json_str)
試したこと
Django側では、こちら やこちら のサイトを参考に、pip install django-cors-headersを行いsettings.pyを以下の部分を追記しました。
INSTALLED_APPS = [
'corsheaders',
]
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
]
CORS_ORIGIN_WHITELIST = (
'http://localhost:8080',
'http://127.0.0.1:8080',
'http://127.0.0.1:8000',
)
CORS_ALLOW_CREDENTIALS = True
CORS_ALLOW_CREDENTIALS = True
また、App.vueファイルの以下hedder部分を削除した状態で、postするとPOST http://127.0.0.1:8000/polls/check/ 403 (Forbidden)とエラーが発生してしまっている状況です。
{
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, PATCH, PUT, DELETE, OPTIONS",
"Access-Control-Allow-Headers": "Origin, Content-Type, X-Auth-Token"
}
},
補足情報(FW/ツールのバージョンなど)
エディター:VScode,OS:Mac OS
どなたか、エラー解決の為、アドバイス頂けましたら幸いです。
追記
Qiita 記事を参考に、axiosにwithCredentials: trueを追記しましたがPOST http://127.0.0.1:8000/polls/check/ 403 (Forbidden)が表示されている状態です。
axios.post(
'http://127.0.0.1:8000/polls/check/',
{
name:this.name,
comment:this.comment
},
{
withCredentials: true
},
)
追記2
こちら の記事を参考に以下の部分をApp.vueに追記しましたが、エラーは解決されていない状況です。
import axios from 'axios';
const headers = {"X-CSRFTOKEN": "<csrf_token_very_long_string_goes_here>"}
axios.postメソッドには、 {headers: headers},を引数に追加しました
ベストアンサー
追記:Vue 公式ドキュメント によって、フロントエンドとバックエンドのサーバーが同一ではない場合、設定の devServer.proxy にバックエンドサーバーのアドレスを入れれば、フロントエンドで知らないリクエストを全部バックエンドに渡せます。
javascript
1 // vue.config.js
2 module . exports = {
3 devServer : {
4 proxy : 'http://localhost:8000'
5 }
6 }
そうしたら、リクエストの際にアドレスを明言する必要がなくなります。
javascript
1 axios . post (
2 '/polls/check/' ,
3 {
4 name : this . name ,
5 comment : this . comment
6 } ,
7 )
追記:そうしてもCSRFを踏んだら、Django側その関数に @csrf_exempt でマークしてください
python
1 @csrf_exempt
2 def check ( ) :
3 pass
AkitoshiManabeさんの言う通り、http://127.0.0.1:8080 と http://localhost:8080との違いで Cross Origin エラーが出てます。
こちらのコードから推測できる誤解を解けておきましょう:
javascript
1 axios . post (
2 'http://127.0.0.1:8000/polls/check/' ,
3 {
4 name : this . name ,
5 comment : this . comment
6 } ,
7 {
8 headers : {
9 "Access-Control-Allow-Origin" : "*" ,
10 "Access-Control-Allow-Methods" : "GET, POST, PATCH, PUT, DELETE, OPTIONS" ,
11 "Access-Control-Allow-Headers" : "Origin, Content-Type, X-Auth-Token"
12 }
13 } ,
14 )
上記の axios の headers はクライアントからサーバーへのリクエストの headers です。例えば、Cookie や Accept など、クライアントができることを示すためです。
Access-Control-Allow-Origin、Access-Control-Allow-Methods、Access-Control-Allow-Headers、この三つの headers はサーバーができることですから、サーバーからクライアントへのレスポンスについてるものです。この三つの headers は axios の headers に入れても意味がありません。削除していいです。
python
1 CORS_ORIGIN_WHITELIST = (
2 'http://localhost:8080' ,
3 'http://127.0.0.1:8080' ,
4 'http://127.0.0.1:8000' ,
5 )
上記の設定をしたら、上記の headers は Django からのレスポンスに CorsMiddleware によって自動的についてるはずですが、カッコを使ってしまい list ではなく tuple を使っていますので、どんな反応してるかわかりません。カッコ () をブラケット [] で書き換えてみたらいかがでしょうか?
オリジン は 「プロトコル + // + ホスト名 + ポート番号 」で成る文字列です。
ブラウザは http://127.0.0.1:8080 と http://localhost:8080 とはクロスオリジンの関係にあるものとして、CORS エラーを吐きます。
エラー解決の為、アドバイス頂けましたら幸いです
他者の記事やコードを真似て、手を動かして確認できているように感じますが、
それぞれの仕組み(なぜ、そのように書けるのか?)について、詳細を再確認してください
活字ばかりだと退屈かもしれませんが、仕組みを覚える と、エラー原因は自身で特定できるようになります。
15分調べてもわからないことは teratailで質問しよう!
ただいまの回答率 85.29%
質問をまとめることで 思考を整理して素早く解決
テンプレート機能で 簡単に質問をまとめる
質問する