質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Redux

Reduxは、JavaScriptアプリケーションの状態を管理するためのオープンソースライブラリです。ReactやAngularで一般的にユーザーインターフェイスの構築に利用されます。

Django

DjangoはPythonで書かれた、オープンソースウェブアプリケーションのフレームワークです。複雑なデータベースを扱うウェブサイトを開発する際に必要な労力を減らす為にデザインされました。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

Q&A

解決済

1回答

2990閲覧

ログイン状態でしか使えないAPIをreact-reduxアプリから叩きたいが、yarn startによるreact開発環境下ではログイン状態でも403になって情報が取得できない。

threeaster

総合スコア14

Redux

Reduxは、JavaScriptアプリケーションの状態を管理するためのオープンソースライブラリです。ReactやAngularで一般的にユーザーインターフェイスの構築に利用されます。

Django

DjangoはPythonで書かれた、オープンソースウェブアプリケーションのフレームワークです。複雑なデータベースを扱うウェブサイトを開発する際に必要な労力を減らす為にデザインされました。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

0グッド

0クリップ

投稿2018/10/04 09:23

前提・実現したいこと

基本的に一つのウィンドウでいろいろ(表示とか作成とか)をやるwebアプリを作成しています。
バックエンドにはdjangoを使用し、認証と、apiの提供などをします。
そして、index.htmlに

<div id="root"></div>

をおいて、またmain.jsを読み込み、トップページ上でreactアプリを動かすようにします。
main.jsは、react-reduxによって作成したものをyarnによってビルドし、ハッシュ値を取り除いた上でdjangoの静的ファイルが読み込める場所にシンボリックリンクを貼っています。

djangoで、あるモデル(Postします)の一覧情報を取得するAPIをrest_frameworkを用いて作成しました。これはログイン状態でないと403になり、ログイン状態ならばログイン中のUserに紐づくPostの一覧がjsonで返ってくるものです。

react-reduxのアプリで、このAPIを叩いて、その内容をactionに入れてdispatchして、それをstateに入れて表示して……とやりたいです。

発生している問題・エラーメッセージ

実際には、yarn startで起動したhttp://localhost:3000で見ることができるreact-reduxのアプリでそのAPIを叩くと、ステータスコード403で、

{"detail":"認証情報が含まれていません。"}

と返ってきてしまいます。あらかじめ別タブでログインしておいてもこうなってしまいます。また、同じくログイン状態で、APIを直接叩いたときはちゃんと情報が取得できますし、ビルドしてdjango側のページから参照されるようにしたものをhttp://localhost:8000から見たときもちゃんと情報がstateに入っているようです。

該当のソースコード

django側

python

1# model.py 2 3from django.db import models 4from django.utils import timezone 5from django.contrib.auth.models import User 6 7class Post(models.Model): 8 title = models.CharField(max_length=200) 9 body = models.CharField(max_length=1000) 10 user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='users') 11 created_at = models.DateTimeField(auto_now_add=True) 12 updated_at = models.DateTimeField(auto_now=True) 13 14 def __str__(self): 15 return self.title

python

1# serializers.py 2 3from rest_framework import serializers 4from .models import Post 5 6class Meta: 7 model = Post 8 fields = ('id', 'title', 'body')

python

1# apis.py 2 3from rest_framework import viewsets 4from rest_framework.permissions import IsAuthenticated 5from .models import Post 6from .serializers import PostSerializer 7 8 9class PostViewSet(viewsets.ModelViewSet): 10 permission_classes = (IsAuthenticated, ) 11 serializer_class = PostSerializer 12 13 def get_queryset(self): 14 return Post.objects.filter(user=self.request.user)

python

1# urls.py 2 3from rest_framework import routers 4from .apis import PostViewSet 5 6 7router = routers.DefaultRouter() 8router.register('posts', PostViewSet, base_name='post')

python

1# settings.pyはlocalとproductionを分けるためにbase.pyで共通のものを、local.pyとproduction.pyで差分を定義しています。 2# 以下はapi関連に関して変更した部分を抜き出したものです。 3 4INSTALLED_APPS = [ 5 'post.apps.PostConfig', 6 'accounts.apps.AccountsConfig', // ログイン、ログアウトのためのアプリ 7 'django.contrib.admin', 8 'django.contrib.auth', 9 'django.contrib.contenttypes', 10 'django.contrib.sessions', 11 'django.contrib.messages', 12 'django.contrib.staticfiles', 13 'rest_framework', 14 'corsheaders' 15] 16 17CORS_ORIGIN_ALLOW_ALL = True # local.pyのみ

react側

javascript

1// index.js 2import React from 'react'; 3import ReactDOM from 'react-dom'; 4import './index.css'; 5import App from './App'; 6import registerServiceWorker from './registerServiceWorker'; 7import { createStore, applyMiddleware } from 'redux' 8import rootReducer from './reducers/index' 9import { Provider } from 'react-redux' 10import createSagaMiddleware from 'redux-saga' 11import { rootSaga } from './sagas' 12import { createLogger } from 'redux-logger' 13 14const sagaMiddleware = createSagaMiddleware() 15const middlewares = [sagaMiddleware] 16if(process.env.NODE_ENV !== 'production'){ 17 const loggerMiddleware = createLogger() 18 middlewares.push(loggerMiddleware) 19} 20const store = createStore(rootReducer, applyMiddleware(...middlewares)) 21 22sagaMiddleware.run(rootSaga, store.dispatch) 23 24ReactDOM.render( 25<Provider store={store}> 26 <App /> 27</Provider>, 28document.getElementById('root')); 29 30registerServiceWorker();

javascript

1// sagas.js 2import * as effects from 'redux-saga/effects' 3import * as call_api from './call_api' 4import * as actions from './actions' 5 6export function* setup(){ 7 const { success, error } = yield effects.call(call_api.post_list) 8 if(success && !error){ 9 yield effects.put(actions.set_post_list(success)) 10 } 11} 12 13export function* rootSaga(dispatch){ 14 yield effects.fork(setup) 15}

javascript

1// call_api.js 2const api_root = process.env.REACT_APP_API_ROOT // http://localhost:8000が入っています 3 4export const site_list = () => { 5 return fetch(api_root + '/api/posts.json', { mode: 'cors' }) 6 .then(response => response.json()) 7 .then((json) => { 8 return { success: json } 9 }).catch((error) => { 10 return { error } 11 }) 12}

javascript

1// actions.js 2 3import * as action_types from './constants/action_types' // export const SET_POST_LIST = 'SET_POST_LIST'とあります 4 5export const set_post_list = (post_list) => { 6 return { type: action_types.SET_POST_LIST, post_list } 7}

試したこと

上記でも書きましたが直接apiを叩いたり、buildしたものを見てみたりしました。その場合はyarn startの環境のみで動きませんでした。
一応chromeとsafariで試しましたがだめでした。
シークレットウィンドウでlocalhost:8000でログインしたあと同一タブでlocalhost:3000にいってみましたがだめでした。
最初の状態ではCORSエラーが出たので、django-cors-headersを入れてそれを回避しています。
gitでどこでエラーが出るようになったのかをさかのぼってみましたが、APIに認証を付けた瞬間からエラーが出るようになったようです。

補足情報(FW/ツールのバージョンなど)

macOS Hight Sierra バージョン10.13.6
google chrome: 69.0.3497.100(Official Build)
Python 3.7.0
venvによる仮想環境下

asn1crypto==0.24.0 cffi==1.11.5 cryptography==2.3.1 Django==2.1 django-cors-headers==2.4.0 django-filter==2.0.0 djangorestframework==3.8.2 idna==2.7 pycparser==2.18 PyMySQL==0.9.2 pytz==2018.5 selenium==3.14.1 six==1.11.0 urllib3==1.23

yarn 1.9.2

"dependencies": { "prop-types": "^15.6.2", "react": "^16.5.2", "react-dom": "^16.5.2", "react-redux": "^5.0.7", "react-scripts": "1.1.5", "redux": "^4.0.0" }, "devDependencies": { "enzyme": "^3.6.0", "enzyme-adapter-react-16": "^1.5.0", "redux-logger": "^3.0.6", "redux-mock-store": "^1.5.3", "redux-saga": "^0.16.0" }

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

自己解決

解決しました。

まず、fetch apiで認証情報を使うときはcredentials: 'include'を含む必要があったようです。
参考: https://developer.mozilla.org/ja/docs/Web/API/Fetch_API/Using_Fetch#Sending_a_request_with_credentials_included

したがって、call_api.jsは以下のようになります。

javascript

1// call_api.js 2const api_root = process.env.REACT_APP_API_ROOT // http://localhost:8000が入っています 3 4export const site_list = () => { 5 return fetch(api_root + '/api/posts.json', { mode: 'cors', credentials: 'include' }) 6 .then(response => response.json()) 7 .then((json) => { 8 return { success: json } 9 }).catch((error) => { 10 return { error } 11 }) 12}

また、これだけだと

The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true' when the request's credentials mode is 'include'. Origin 'http://localhost:3000' is therefore not allowed access.

と怒られてしまうので、settings.pyに、'Access-Control-Allow-Credentials'を付け加える必要があります。

具体的には以下のようにします。

python

1# settings.pyはlocalとproductionを分けるためにbase.pyで共通のものを、local.pyとproduction.pyで差分を定義しています。 2# 以下はapi関連に関して変更した部分を抜き出したものです。 3 4INSTALLED_APPS = [ 5 'post.apps.PostConfig', 6 'accounts.apps.AccountsConfig', // ログイン、ログアウトのためのアプリ 7 'django.contrib.admin', 8 'django.contrib.auth', 9 'django.contrib.contenttypes', 10 'django.contrib.sessions', 11 'django.contrib.messages', 12 'django.contrib.staticfiles', 13 'rest_framework', 14 'corsheaders' 15] 16 17CORS_ORIGIN_ALLOW_ALL = True # local.pyのみ 18CORS_ALLOW_CREDENTIALS = True # local.pyのみ

参考: https://pypi.org/project/django-cors-headers/

以上2点を修正することでyarn start条件下でもapiから情報を取得できるようになりました。

投稿2018/10/09 06:51

threeaster

総合スコア14

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問