zoukankan      html  css  js  c++  java
  • djangorestframework+vue-cli+axios,为axios添加token作为headers踩坑记

    情况是这样的,项目用的restful规范,后端用的django+djangorestframework,前端用的vue-cli框架+webpack,前端与后端交互用的axios,然后再用户登录之后,axios添加token作为axios的header并请求后端,后端部分用的djangorestframework的认证组件。

    以上的相关知识,不是本篇文章的重点,请移步:

    前后端分离djangorestframework——认证组件

    vue(9)—— 组件化开发 - webpack(3)

    vue(6)—— vue中向后端异步请求

    postman测试

    在最开始写好后端

    认证组件:

    视图部分装饰认证组件:

    vue部分,做了个判断,如果用户是登录状态,自动设置默认的headers:

    添加了请求拦截器之后,前端会自动对每个请求之前请求一次,请求方式为OPTIONS,之后再发出真实的请求

    关于这个为什么会做两次请求是因为:

    浏览器会对复杂请求进行处理,在发送真正的请求前, 会先发送一个方法为OPTIONS的预请求(preflight request), 用于试探服务端是否能接受真正的请求,如果options获得的回应是拒绝性质的,比如404403500等http状态,就会停止post、put等请求的发出

    有三种方式会导致这种现象:

    • 请求方法不是GET/HEAD/POST。即复杂请求
    • POST请求的Content-Type并非application/x-www-form-urlencoded, multipart/form-data, 或text/plain。最常见的json就不是
    • 请求设置了自定义的header字段。我这里就设置了token作为自定义的headers

    用的postman做的测试:

    返回结果:

    项目真实测试 

    然后在项目真实测试的时候:

    前端用的vue-cli +webpack,启动项目,并抓包查看时,请求状态500

    并且请求的参数并没有给上header

    后端就是报错:

     就是这个:

    TypeError: cannot unpack non-iterable AuthenticationFailed object

    并且前端的console部分还报同源策略的错:

    我跟你说,你要是跑去后端设置中间件的response的话,你就距离正确答案越来越远了,我的中间件部分是这样的:

    然后根据前面用postman测试都没问题,所以我判定,一定不是中间件的问题

    思来想去,根本的原因就是拿不到token,所以我开始在这方面思考,然后我注释了那段是否带有token的判断,再测试:

    打印request.META

    注释掉验证部分,只是打印看看request.META里的数据

    前端再次请求:

    OPTIONS请求方式因为已经取消了验证所以不报错了:

    第二次真实请求也出现了,并且返回状态码200

     header部分也带上了token:

     

    也就是说,前端装饰上了token的,但是后端没有拿到,所以报错了

    最后看看,后端print(request.META)

    因为有两次请求,看看两次到底有什么不同(我已经删除掉了一些无关精要的数据)

    第一次请求时:

    {'ALLUSERSPROFILE':'RUN_MAIN': 'true', 'SERVER_NAME': 'www.xmind.net', 'GATEWAY_INTERFACE': 'CGI/1.1', 'SERVER_PORT': '8000', 'REMOTE_HOST': '', 'CONTENT_LENGTH': '', 'SCRIPT_NAME': '', 'SERVER_PROTOCOL': 'HTTP/1.1', 'SERVER_SOFTWARE': 'WSGIServer/0.2', 'REQUEST_METHOD': 'OPTIONS', 'PATH_INFO': '/api/v1/', 'QUERY_STRING': '', 'REMOTE_ADDR': '127.0.0.1', 'CONTENT_TYPE': 'text/plain', 'HTTP_HOST': '127.0.0.1:8000', 'HTTP_CONNECTION': 'keep-alive', 'HTTP_ACCESS_CONTROL_REQUEST_METHOD': 'GET', 'HTTP_ORIGIN': 'http://localhost:8080', 'HTTP_USER_AGENT': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3738.0 Safari/537.36 Edg/75.0.107.0', 'HTTP_ACCESS_CONTROL_REQUEST_HEADERS': 'authorization', 'HTTP_ACCEPT': '*/*', 'HTTP_REFERER': 'http://localhost:8080/Course', 'HTTP_ACCEPT_ENCODING': 'gzip, deflate, br', 'HTTP_ACCEPT_LANGUAGE': 'zh-CN,zh;q=0.9,en;q=0.8,en-US;q=0.7', 'wsgi.input': <_io.BufferedReader name=628>, 'wsgi.errors': <_io.TextIOWrapper name='<stderr>' mode='w' encoding='UTF-8'>, 'wsgi.version': (1, 0), 'wsgi.run_once': False, 'wsgi.url_scheme': 'http', 'wsgi.multithread': True, 'wsgi.multiprocess': False, 'wsgi.file_wrapper': <class 'wsgiref.util.FileWrapper'>}

    第二次请求时:

    {'ALLUSERSPROFILE': 'RUN_MAIN': 'true', 'SERVER_NAME': 'www.xmind.net', 'GATEWAY_INTERFACE': 'CGI/1.1', 'SERVER_PORT': '8000', 'REMOTE_HOST': '', 'CONTENT_LENGTH': '', 'SCRIPT_NAME': '', 'SERVER_PROTOCOL': 'HTTP/1.1', 'SERVER_SOFTWARE': 'WSGIServer/0.2', 'REQUEST_METHOD': 'GET', 'PATH_INFO': '/api/v1/', 'QUERY_STRING': '', 'REMOTE_ADDR': '127.0.0.1', 'CONTENT_TYPE': 'text/plain', 'HTTP_HOST': '127.0.0.1:8000', 'HTTP_CONNECTION': 'keep-alive', 'HTTP_ACCEPT': 'application/json, text/plain, */*', 'HTTP_ORIGIN': 'http://localhost:8080', 'HTTP_AUTHORIZATION': '626d34f7-2302-4bb0-a012-5daf0f588d8c', 'HTTP_USER_AGENT': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3738.0 Safari/537.36 Edg/75.0.107.0', 'HTTP_REFERER': 'http://localhost:8080/Course', 'HTTP_ACCEPT_ENCODING': 'gzip, deflate, br', 'HTTP_ACCEPT_LANGUAGE': 'zh-CN,zh;q=0.9,en;q=0.8,en-US;q=0.7', 'wsgi.input': <_io.BufferedReader name=632>, 'wsgi.errors': <_io.TextIOWrapper name='<stderr>' mode='w' encoding='UTF-8'>, 'wsgi.version': (1, 0), 'wsgi.run_once': False, 'wsgi.url_scheme': 'http', 'wsgi.multithread': True, 'wsgi.multiprocess': False, 'wsgi.file_wrapper': <class 'wsgiref.util.FileWrapper'>}

    发现前面一大段都相同,就从请求方式开始有不同的,所以我重新设置了认证组件。

    因为一个请求方式是OPTIONS,一个是GET,并且看前端部分,当请求方式是OPTIONS的时候因为是浏览器自动发的预请求,所以没有按我们设定的带上自定义的header,也就没有Authorization-token这个参数了

    终于发现了问题所在,最后在后端做了个判断,当请求方式是OPTIONS的时候,跳过验证,然后完美解决:

    前端请求:没问题,都是200

    并且后端确实可以打印出对应的用户名和token:

    好的,踩坑完毕,感谢查看

  • 相关阅读:
    java开发中的重中之重-------mysql(基础篇)
    开发中的重点-----设计模式
    java 不可不知的数据库知识-----事物
    redis 入门笔记
    转 Java对日期Date类进行加减运算一二三
    Ajax 中的高级请求和响应
    Ajax之基础总结
    Spring中的国际化资源以及视图跳转
    javascript基础总结
    SpringMVC的表单标签
  • 原文地址:https://www.cnblogs.com/Eeyhan/p/10711144.html
Copyright © 2011-2022 走看看