最新消息:20210917 已从crifan.com换到crifan.org

【已解决】Chrom中js去POST本地Django的API出错:The value of the Access-Control-Allow-Origin header in the response must not be the wildcard * when the request’s credentials mode is include

chrome crifan 7213浏览 0评论

别人的代码:

antd 的reactjs的web页面,去登录,出错:

<code>Failed to load http://localhost:65000/api/v1/jwt-token-auth/: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. Origin 'http://localhost:8000' is therefore not allowed access.
index.js:2177 uncaught at _callee3 at _callee3
at _callee6
at takeEvery(login/login, _callee)
at _callee
at _callee
Error: TypeError: Cannot set property 'status' of undefined
    at login$ (http://localhost:8000/index.js:16499:31)
    at tryCatch (http://localhost:8000/index.js:33388:40)
    at Generator.invoke [as _invoke] (http://localhost:8000/index.js:33622:22)
    at Generator.prototype.(anonymous function) [as next] (http://localhost:8000/index.js:33440:21)
    at next (http://localhost:8000/index.js:70781:27)
    at currCb (http://localhost:8000/index.js:70858:7)
    at http://localhost:8000/index.js:70108:17
    at http://localhost:8000/index.js:71719:26
    at onError (http://localhost:8000/index.js:70109:11)
    at sagaWithCatch$ (http://localhost:8000/index.js:72119:13)
    at tryCatch (http://localhost:8000/index.js:33388:40)
    at Generator.invoke [as _invoke] (http://localhost:8000/index.js:33622:22)
    at Generator.prototype.(anonymous function) [as throw] (http://localhost:8000/index.js:33440:21)
    at next (http://localhost:8000/index.js:70759:32)
    at Object.currCb [as cont] (http://localhost:8000/index.js:70858:7)
    at end (http://localhost:8000/index.js:70826:23)
    at abort (http://localhost:8000/index.js:70549:5)
    at Object.task.cont (http://localhost:8000/index.js:70562:9)
    at next (http://localhost:8000/index.js:70798:16)
    at currCb (http://localhost:8000/index.js:70858:7)
__stack_frame_overlay_proxy_console__ @ index.js:2177
log @ utils.js:240
logError @ proc.js:221
。。。
batchedUpdates @ react-dom.development.js:2131
dispatchEvent @ react-dom.development.js:4555
interactiveUpdates$1 @ react-dom.development.js:16714
interactiveUpdates @ react-dom.development.js:2150
dispatchInteractiveEvent @ react-dom.development.js:4532
request.js:72 Fetch finished loading: OPTIONS "http://localhost:65000/api/v1/jwt-token-auth/".
</code>

对于此问题:

之前实际上是访问的在线的:

47.x.x.x的接口

也是同样问题:

别人告诉我说,自己肯定是已经实现了CORS

-》其都是连接的本地的Server去调试的,就没有这个问题

-〉而上面看到的,是已经花了九牛二虎之力,终于跑起来其写的本地的Django的代码了,但是错误依旧。

去搜了下的代码

Object.task.cont

currCb

代码里都搜不到

-》好像这个错误不是自己的代码

像是Reactjs或Antd中的。

不过,还是先要去解决第一个错误:

<code>Failed to load http://localhost:65000/api/v1/jwt-token-auth/: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. Origin 'http://localhost:8000' is therefore not allowed access.
</code>

看起来是:

Django的jwt-token-auth导致的

换了safari,错误信息是类似的

然后别人那里是没有问题的,其log是:

Fetch finished loading: OPTIONS “http://localhost:65000/api/v1/jwt-token-auth/“.

而此处是在这条log之前,出现的错误。

Failed to load jwt-token-auth

Failed to load jwt-token-auth Access-Control-Allow-Origin

django Failed to load jwt-token-auth Access-Control-Allow-Origin

django Failed to load jwt-token-auth

“No ‘Access-Control-Allow-Origin’ header is present on the requested resource” in django – Stack Overflow

ottoyiu/django-cors-headers: Django app for handling the server headers required for Cross-Origin Resource Sharing (CORS)

去试试这个

<code>➜  xxx git:(master) ✗ pip3 install django-cors-headers
Requirement already satisfied: django-cors-headers in /usr/local/lib/python3.6/site-packages (2.2.0)
</code>

发现已经安装和设置参数了。

然后再去加上:

<code>CORS_ORIGIN_ALLOW_ALL = True
</code>

看看结果

问题依旧。

加了:

<code>
CORS_ORIGIN_ALLOW_ALL = True
CORS_ORIGIN_WHITELIST = ('*', 'localhost:8001', 'localhost:8000', 'localhost:65000')
CORS_ALLOW_METHODS = (
'DELETE',
'GET',
'OPTIONS',
'PATCH',
'POST',
'PUT',
)
CORS_ALLOW_HEADERS = (
'accept',
'accept-encoding',
'authorization',
'content-type',
'dnt',
'origin',
'user-agent',
'x-csrftoken',
'x-requested-with',
)
CORS_ALLOW_CREDENTIALS = True
</code>

问题依旧。

python – Django Rest Framework JWT – Stack Overflow

django restframework token Authentication fail with “invalid token” – Stack Overflow

Ionic2 JWT authentication failed with Django rest framework backend – Stack Overflow

python – Django Rest Framework – Authentication credentials were not provided – Stack Overflow

python – How to test authentication using REST Framework JWT? – Stack Overflow

感觉是:

此处的django-cors-headers就没起效果,导致CORS失败

django-cors-headers not working

python – django-cors-headers not work – Stack Overflow

<code>CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_CREDENTIALS = False
</code>

结果:

再去看看:

<code>Failed to load http://localhost:65000/api/v1/jwt-token-auth/: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. Origin 'http://localhost:8000' is therefore not allowed access.
</code>

试试:

去掉CORS_ORIGIN_WHITELIST中的*

<code>CORS_ORIGIN_ALLOW_ALL = True
CORS_ORIGIN_WHITELIST = ('localhost:8001', 'localhost:8000', 'localhost:65000')
CORS_ALLOW_CREDENTIALS = False
</code>

结果:问题依旧。

试试:

<code>CORS_ORIGIN_ALLOW_ALL = True
CORS_ORIGIN_WHITELIST = ('localhost:8001', 'localhost:8000', 'localhost:65000')
CORS_ALLOW_CREDENTIALS = True
</code>

结果:问题依旧。

有:

access-control-allow-origin:*

返回。

python – django-cors-headers not working at all – Stack Overflow

python – django-cors-headers settings.py django app not working even though I’ve added all the requirements to settings.py – Stack Overflow

Django 1.9 + django-cors-headers + AJAX not working – Stack Overflow

说:Django-cors-headers 已经失效

建议换:Django-cors-middleware

jquery – Django-cors-headers not working – Stack Overflow

Enable Django CORS (Cross Origin Resource Sharing) Headers configuration · crs4/ome_seadragon Wiki

确保CommonMiddleware在最后:

<code>MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'corsheaders.middleware.CorsMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.middleware.common.CommonMiddleware',
]
</code>

也不行。

再换个位置:

<code>'django.middleware.csrf.CsrfViewMiddleware',
'corsheaders.middleware.CorsMiddleware',
</code>

结果:问题依旧。

CorsMiddleware is not working in Django 1.10 · Issue #102 · ottoyiu/django-cors-headers

搞不定。

再去找找另外的问题

index.js uncaught at _callee3 at _callee3

Error: TypeError: Cannot set property ‘status’ of undefined

参数不对出现uncaught at _callee3问题再次进行操作无法进行 · Issue #1446 · dvajs/dva

request.js中fetch执行后浏览器console抛出异常 · Issue #1068 · dvajs/dva

通过调试代码:

xx/src/index.js

<code>import './index.less';
// 1. Initialize
const app = dva({
  history: createHistory(),
  onError: (err, dispatch) =&gt; {
    console.log("err=", err)
    console.log("err.response=", err.response)
    console.log("dispatch=", dispatch)

    // if (err.response) {
    //   console.log("err.response=", err.response)
    //   console.log("dispatch=", dispatch)
    // }
  },
});
</code>

xx/src/models/login.js

<code>  effects: {
    *login({ payload }, { call, put }) {
      console.log("payload=", payload)
      console.log("call=", call)
      console.log("put=", put)

      const response = yield call(getUserToken, payload);
      console.log("response=", response)
      response.status = 'ok'
      response.type = 'account'
</code>

发现:

后面的错误:

Error: TypeError: Cannot set property ‘status’ of undefined

是代码:

response.status = ‘ok’

导致的,原因是:

此时的response是空

-》而response是空的原因是:

CORS错误,导致无法正常返回response

-〉所以:

后面的代码没有问题

还是要先去解决CORS的问题。

试试:

https://github.com/zestedesavoir/django-cors-middleware

<code>➜  xx git:(master) ✗ pip3 install django-cors-middleware
Collecting django-cors-middleware
  Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ConnectTimeoutError(&lt;pip._vendor.urllib3.connection.VerifiedHTTPSConnection object at 0x109998390&gt;, 'Connection to files.pythonhosted.org timed out. (connect timeout=15)')': /packages/33/d8/23f4b1249021f0192a3d6f263c29b46637c1f03ab41608ed8477d992550d/django-cors-middleware-1.3.1.tar.gz
  Downloading https://files.pythonhosted.org/packages/33/d8/23f4b1249021f0192a3d6f263c29b46637c1f03ab41608ed8477d992550d/django-cors-middleware-1.3.1.tar.gz
Building wheels for collected packages: django-cors-middleware
  Running setup.py bdist_wheel for django-cors-middleware ... done
  Stored in directory: /Users/crifan/Library/Caches/pip/wheels/1c/bd/91/bb2ee8ca87deb8c32db5d0356112f0e9b4abde22221e5d502c
Successfully built django-cors-middleware
Installing collected packages: django-cors-middleware
Successfully installed django-cors-middleware-1.3.1
</code>

然后把去掉

django-cors-headers

换成:

django-cors-middleware

问题依旧。

还是换回去:

django-cors-headers

https://github.com/ottoyiu/django-cors-headers

“If True, the whitelist will not be used and all origins will be accepted.”

所以,已经:

CORS_ORIGIN_ALLOW_ALL = True

就去掉:

<code># CORS_ORIGIN_WHITELIST = ('*', 'localhost:8001', 'localhost:8000', 'localhost:65000')
# CORS_ORIGIN_WHITELIST = ('localhost:8001', 'localhost:8000', 'localhost:65000')
</code>

结果:问题依旧。

The value of the ‘Access-Control-Allow-Origin’ header in the response must not be the wildcard ‘*’ when the request’s credentials mode is ‘include’

ajax – CORS: Cannot use wildcard in Access-Control-Allow-Origin when credentials flag is true – Stack Overflow

java – Header in the response must not be the wildcard ‘*’ when the request’s credentials mode is ‘include’ – Stack Overflow

javascript – CORS: credentials mode is ‘include’ – Stack Overflow

Django must not be the wildcard ‘*’ when the request’s credentials mode is ‘include’

Header in the response must not be the wildcard ‘*’ when the request’s credentials mode is ‘include’ · Issue #227 · sockjs/sockjs-node

Using Fetch – Web APIs | MDN

Error: A wildcard ‘*’ cannot be used in the ‘Access-Control-Allow-Origin’ · Issue #177 · sockjs/sockjs-node

fetch 带cookie跨域访问 – SegmentFault 思否

axios的cookie跨域以及相关配置 – 个人文章 – SegmentFault 思否

记一次header跨域与cookie共享 – andy_chan – 博客园

Django   the request’s credentials mode is ‘include’

Response to preflight request doesn’t pass access control check: 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’ · Issue #200 · corydolphin/flask-cors

看本地的Django的log是:

<code>➜  xx git:(master) ✗ python3 ./manage.py runserver_plus 65000
* Running on http://127.0.0.1:65000/ (Press CTRL+C to quit)
* Restarting with stat
Performing system checks...

System check identified no issues (0 silenced).

Django version 2.0.6, using settings 'conf.development.settings'
Development server is running at http://[127.0.0.1]:65000/
Using the Werkzeug debugger (http://werkzeug.pocoo.org/)
Quit the server with CONTROL-C.
* Debugger is active!
* Debugger PIN: 119-413-930
127.0.0.1 - - [06/Jul/2018 15:49:27] "OPTIONS /api/v1/jwt-token-auth/ HTTP/1.1" 200 -

</code>

-》看来是:

需要把host加上127.0.0.1?

并且也注意到:

127.0.0.1 – – [06/Jul/2018 15:49:27] “OPTIONS /api/v1/jwt-token-auth/ HTTP/1.1” 200 –

表示此处的CORS的OPTIONS,是支持了的

但是对于后续的login的POST出错了。

试试:

<code>CORS_ORIGIN_WHITELIST = (
'localhost:8001',
'localhost:8000',
'localhost:65000',
'127.0.0.1:8001',
'127.0.0.1:8000',
'127.0.0.1:65000',
)
</code>

结果:

http://localhost:8000/#/user/login

错误依旧。

难道是本地的Python版本的问题?

此处用的是:

/usr/local/lib/python3.6/

别人(没有CORS问题)用的是:

/usr/local/var/pyenv/versions/3.6.3/lib/python3.6

django Access-Control-Allow-Origin  header in the response must not be the wildcard ‘*’ when the request’s credentials mode is ‘include’

django fetch Access-Control-Allow-Origin  header in the response must not be the wildcard ‘*’ when the request’s credentials mode is ‘include’

Allow * for Access-Control-Allow-Headers and Access-Control-Allow-Methods · Issue #251 · whatwg/fetch

js网络请求跨域问题汇总(携带cookie) – 简书

javascript – No ‘Access-Control-Allow-Origin’ header is present on the requested resource—when trying to get data from a REST API – Stack Overflow

Cross-Origin Resource Sharing (CORS) – HTTP | MDN

最后此处经过调试是:

实际上此处的django-cors-headers是工作了的

然后对于:

如果Chrome中没有启动CORS插件:

那么几种配置:

<code>CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_CREDENTIALS = True
</code>

或:

<code>CORS_ORIGIN_WHITELIST = ('*', 'localhost:8001', 'localhost:8000', 'localhost:65000')
CORS_ALLOW_CREDENTIALS = True
</code>

其中包含了自己此处的地址:

http://localhost:8000/#/user/login/

对应的:

localhost:8000

或:

<code>CORS_ORIGIN_WHITELIST = (
'localhost:8001',
'localhost:8000',
'localhost:65000',
# '127.0.0.1:8001',
# '127.0.0.1:8000',
# '127.0.0.1:65000',
)
</code>

都是可以工作的,都可以正常登录:

但是如果开启了Chrome的CORS插件:

那么上面的配置,无论如何,都无法生效,都无法登录,出现前面的错误:

<code>Failed to load http://localhost:65000/api/v1/jwt-token-auth/: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. Origin 'http://localhost:8000' is therefore not allowed access.
</code>

而另外,对于前端代码

其中给fetch的(去登录时的)POST加上:

<code>credentials: 'include',
</code>

-》

方式1:

xx/src/utils/request.js

中加上:

<code>export default function request(url, options) {
  const defaultOptions = {
    credentials: 'include',
  };
  const newOptions = { ...defaultOptions, ...options };
  if (newOptions.method === 'POST' || newOptions.method === 'PUT' || newOptions.method === 'PATCH') {
    newOptions.credentials = 'include'
    if (!(newOptions.body instanceof FormData)) {
</code>

或:

方式2:

xx/src/services/api.js

中加上:

<code>export async function getUserToken(params) {
  return request(`${apiHost}${apiVersion}/jwt-token-auth/`, {
    method: 'POST',
    credentials : 'include',
    body: params,
  });
}
</code>

然后发现其实:

xx/src/utils/request.js

已经有了:

<code>  const defaultOptions = {
    credentials: 'include',
  };
</code>

所以去掉了,也不影响前面测试的效果。

【总结】

对于此处错误:

<code>Failed to load http://localhost:65000/api/v1/jwt-token-auth/: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. Origin 'http://localhost:8000' is therefore not allowed access.
</code>

的解释是:

如果你的请求(此处是web前端中js中的fetch)的credentials是include模式的话

更多的可能的值,详见:

使用 Fetch – Web API 接口 | MDN

<code>postData('http://example.com/answer', {answer: 42})
  .then(data =&gt; console.log(data)) // JSON from `response.json()` call
  .catch(error =&gt; console.error(error))

function postData(url, data) {
  // Default options are marked with *
  return fetch(url, {
    body: JSON.stringify(data), // must match 'Content-Type' header
    cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
    credentials: 'same-origin', // include, same-origin, *omit
    headers: {
      'user-agent': 'Mozilla/4.0 MDN Example',
      'content-type': 'application/json'
    },
    method: 'POST', // *GET, POST, PUT, DELETE, etc.
    mode: 'cors', // no-cors, cors, *same-origin
    redirect: 'follow', // manual, *follow, error
    referrer: 'no-referrer', // *client, no-referrer
  })
  .then(response =&gt; response.json()) // parses response to JSON
}
</code>

的:

  • same-origin

  • omit

就不应该:

<code>Access-Control-Allow-Origin: *
</code>

然后最后找到的原因是:

此处Chrome(之前安装了的)CORS插件是开启了的:

从而导致出错的。

而正确的做法是:

确保此处的Chrome的CORS插件(如果有的话),不要开启,是关闭的:

然后去使用如下配置:

最终,Django(版本:2.0.6)中对于django-cors-headers(版本:2.2.0)来说,相关配置:

<code>INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'django.contrib.sites',
    'rest_framework',
    'corsheaders',
    'rest_framework_swagger',
    'django_extensions',
    'apps.core',
    'apps.user',
    'apps.script',
]
</code>

其中

‘corsheaders’,

放在中间即可。

<code>MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
</code>

其中:

corsheaders.middleware.CorsMiddleware

放在最上面

尤其是要在:

django.middleware.common.CommonMiddleware

的前面。

<code>CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_CREDENTIALS = True
</code>

即可。

而其中的

CORS_ORIGIN_ALLOW_ALL = True

可以换成:

<code>CORS_ORIGIN_ALLOW_ALL = False
CORS_ORIGIN_WHITELIST = (
    'localhost:8001',
    'localhost:8000',
    'localhost:65000',
    # '127.0.0.1:8001',
    # '127.0.0.1:8000',
    # '127.0.0.1:65000',
)
</code>

或:

<code>CORS_ORIGIN_ALLOW_ALL = False
CORS_ORIGIN_WHITELIST = ('*', 'localhost:8001', 'localhost:8000', 'localhost:65000')
</code>

意思是:

不是允许allow所有all的origin,只允许whitelist(白名单)中的这些值

其中的:

localhost:8000

对应着此处的web前端的地址:

http://localhost:8000/#/user/login/

然后,Django后台log才正常,OPTIONS后,才能正常POST:

<code>➜  xx git:(master) ✗ python3 ./manage.py runserver_plus 65000
* Running on http://127.0.0.1:65000/ (Press CTRL+C to quit)
* Restarting with stat
Performing system checks...

System check identified no issues (0 silenced).

Django version 2.0.6, using settings 'conf.development.settings'
Development server is running at http://[127.0.0.1]:65000/
Using the Werkzeug debugger (http://werkzeug.pocoo.org/)
Quit the server with CONTROL-C.
* Debugger is active!
* Debugger PIN: 119-413-930
* Detected change in '/Users/crifan/dev/dev_root/company/xx/conf/development/settings.py', reloading
* Restarting with stat
Performing system checks...
...
127.0.0.1 - - [06/Jul/2018 16:41:28] "OPTIONS /api/v1/jwt-token-auth/ HTTP/1.1" 200 -
127.0.0.1 - - [06/Jul/2018 16:41:28] "POST /api/v1/jwt-token-auth/ HTTP/1.1" 200 -
127.0.0.1 - - [06/Jul/2018 16:41:28] "OPTIONS /api/v1/users/current_user/ HTTP/1.1" 200 -
127.0.0.1 - - [06/Jul/2018 16:41:29] "GET /api/v1/users/current_user/ HTTP/1.1" 200 -
127.0.0.1 - - [06/Jul/2018 16:41:29] "OPTIONS /api/v1/scripts/? HTTP/1.1" 200 -
127.0.0.1 - - [06/Jul/2018 16:41:29] "GET /api/v1/scripts/? HTTP/1.1" 200 -
</code>

更多解释详见:

https://github.com/ottoyiu/django-cors-headers

【后记】

后来才发现,原来前面这个帖子:

https://stackoverflow.com/questions/43871637/no-access-control-allow-origin-header-is-present-on-the-requested-resource-whe

中已经提到了:

Chrome的CORS插件

只是做了一件事情:给response中的header中插入一个:

<code>Access-Control-Allow-Origin: *
</code>

-》而如果插件更加智能的话,应该插入:

<code>Access-Control-Allow-Origin: http://localhost:8000
</code>

其中

http://localhost:8000

是此处request的origin

所以结论是:

避免使用Chrome的CORS插件。

而此处经过上面的测试,确定Chrome的CORS插件,至少会导致此处的CORS的问题,所以还是以后尽量不用Chrome的CORS插件了。

【后记】

如果不用CORS插件,暂时又不想要删除,可以去禁用:

转载请注明:在路上 » 【已解决】Chrom中js去POST本地Django的API出错:The value of the Access-Control-Allow-Origin header in the response must not be the wildcard * when the request’s credentials mode is include

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
94 queries in 0.194 seconds, using 23.49MB memory