背景
在开发一个简单后台分析统计的时候,因为涉及到了前端和后端接口进行联调的问题,而且前端主要是使用Vue.js来相关开发,在使用axios和本地的后端接口进行联调的时候遇到了一个跨域的问题。
如图示:
前端的请求接口:
image.png
后端接口服务:
image.png image.png
问题描述:
按理说跨域如果后端不支持的话,要想前端完成请求处理,需要进行使用nginx转发处理。
但是既然是本地调试,我们后端直接开启支持即可。
以下是bollte开启支持跨域的代码:
@hook('after_request')
def enable_cors():
"""
钩子函数,处理请求路由之后需要做什么的事情
:return:
"""
response.headers['Access-Control-Allow-Origin'] = '*'
如果你使用的是get提交的话是没问题的:
image.png
使用get提交没有添加
response.headers['Access-Control-Allow-Origin'] = '*'
会出现以下的错误
image.png添加后是:可以返回了数据结果
image.png可惜不幸的是:当你使用POST提交的时候还是遇到405不支持跨域的问题:
POST提交请求:
C2S_Login (data) {
// 登录
return this.action_post('http://127.0.0.1:8189/api/user/login/',data)
},
请求结果:
image.png
问题分析:
xhr.js:178 OPTIONS http://127.0.0.1:8189/api/user/login/ 405 (Method Not Allowed)
查看请求对应的头部信息:
image.png我提交的是POST 怎么变成了OPTIONS
尝试把:
@post('/api/user/login/')
@get('/api/user/login/')
def callback():
return web_helper.return_msg(200, '登入成功!')
变为:
@route('/api/user/login/', method='POST')
def callback():
return web_helper.return_msg(200, '登入成功!')
可惜还是不行:
按其他的方案处理:
def allow_cross_domain(fn):
def _enable_cors(*args, **kwargs):
# set cross headers
response.headers['Access-Control-Allow-Origin'] = '*'
response.headers['Access-Control-Allow-Methods'] = 'GET,POST,PUT,OPTIONS'
allow_headers = 'Referer, Accept, Origin, User-Agent'
response.headers['Access-Control-Allow-Headers'] = allow_headers
if request.method != 'OPTIONS':
# actual request; reply with the actual response
return fn(*args, **kwargs)
return _enable_cors
@route('/api/user/login/', method='POST')
@allow_cross_domain
def callback():
return web_helper.return_msg(200, '登入成功!')
这时候出现还是405 但是不是说是跨域错误的问题,而是另一种错误!
image.png参考:
https://www.cnblogs.com/SilenceTom/p/6697484.html
修改了对应的装饰器可惜还是不行!
def allow_cross_domain(fn):
def _enable_cors(*args, **kwargs):
# set cross headers
response.headers['Access-Control-Allow-Origin'] = '*'
response.headers['Access-Control-Allow-Methods'] = 'GET,POST,PUT,OPTIONS'
allow_headers = 'Referer, Accept, Origin, User-Agent,X-Requested-With, Content-Type, X-File-Name'
response.headers['Access-Control-Allow-Headers'] = allow_headers
if request.method != 'OPTIONS':
# actual request; reply with the actual response
return fn(*args, **kwargs)
return _enable_cors
最终不经意发现原来焕哥大佬已经把这个问题的答案说了!!!感谢大佬!不然还真不知道怎么处理这问题!
问题解决的答案地址:https://www.cnblogs.com/EmptyFS/p/6895479.html
大神就是大神!建议大家都膜拜一下这个大神!也可以加入的他的群多多学习
更多内容,敬请观注他的博客哟,他写的一系列的bottle都是很不错的:
地址:http://www.cnblogs.com/EmptyFS/
我按方法2处理之后post就完美返回了!:
image.png考虑修改源码的方式侵入比较强,不方便后期扩展,可能把bottle给遗漏了!!所有最后还是修改为了再钩子文件处理,按方案1的方式!
最后修改的的代码:
#!/usr/bin/evn python
# coding=utf-8
"""
Author = zyx
@Create_Time: 2017/11/30 18:12
@version: v1.0.0
@Contact: 308711822@qq.com
@File: main.py
@文件功能描述:
"""
import logging
import os
import sys
import bottle
from beaker.middleware import SessionMiddleware
from bottle import TEMPLATE_PATH
from bottle import default_app, run, hook, request, response, get, error, abort
from business_logic import api_offer
# 引入该项目所有用到的API接口
# from api_offer import config, proxy_address_multiple, order_code, order
from abase_framework_module.net_workers import web_helper
from abase_framework_module.cache_workers import redis_cache_helper as cache_helper
from business_logic.app_configs import redis_config
# from api_offer import app_configs
#############################################
# 初始化bottle框架相关参数----应用程序的主入口文件
# 调用的时候
#############################################
# 获取本脚本所在的路径
pro_path = os.path.split(os.path.realpath(__file__))[0]
sys.path.append(pro_path)
# 设置当前bottle运行提交的最大数据值为2M
bottle.BaseRequest.MEMFILE_MAX = 1024 * 1024 * 2
# 定义静态文件目录路径
static_path = os.path.join(pro_path, 'template')
# 定义模板路径
TEMPLATE_PATH.append(os.path.join(pro_path, 'template'))
# 如果不存在log文件夹, 则再当前脚本目录下创建log文件夹存放日志文件-
if not os.path.exists('log'):
os.mkdir('log')
# 定义日志目录
log_path = os.path.join(pro_path, 'log')
# print('当前日志路径------', log_path)
# 定义日志输出格式-输出是信息等级的
logging.basicConfig(level=logging.INFO,
format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
filename="%s/info.log" % log_path,
filemode='a')
# 设置session参数
session_opts = {
'session.type': 'file',
'session.cookie_expires': 3600,
'session.data_dir': '/tmp/sessions/order',
'session.auto': True
}
def allow_cross_domain(fn):
def _enable_cors(*args, **kwargs):
# set cross headers
response.headers['Access-Control-Allow-Origin'] = '*'
response.headers['Access-Control-Allow-Methods'] = 'GET,POST,PUT,OPTIONS'
allow_headers = 'Referer, Accept, Origin, User-Agent,X-Requested-With, Content-Type, X-File-Name'
response.headers['Access-Control-Allow-Headers'] = allow_headers
print('打印!!request.method!', request.method)
if request.method == 'OPTIONS':
# actual request; reply with the actual response
print('打印!!!')
response.close()
return fn(*args, **kwargs)
return _enable_cors
@hook('before_request')
def validate():
"""
钩子函数,处理请求路由之前需要做什么的事情
:return:
"""
"""使用勾子处理页面或接口访问事件"""
# 让bottle框架支持jquery ajax的RESTful风格的PUT和DELETE等请求
REQUEST_METHOD = request.environ.get('REQUEST_METHOD')
HTTP_ACCESS_CONTROL_REQUEST_METHOD = request.environ.get('HTTP_ACCESS_CONTROL_REQUEST_METHOD')
if REQUEST_METHOD == 'OPTIONS' and HTTP_ACCESS_CONTROL_REQUEST_METHOD:
request.environ['REQUEST_METHOD'] = HTTP_ACCESS_CONTROL_REQUEST_METHOD
if request.method == 'OPTIONS':
# actual request; reply with the actual response
print('打印!!!')
# 获取当前访问的Url路径
path_info = request.environ.get("PATH_INFO")
# 过滤不用做任何操作的路由
if path_info in ['/favicon.ico', '/check_err/', '/log/']:
return ''
# 记录客户端提交参数信息----实测是成功
web_helper.write_request_log(path_info)
@hook('after_request')
@allow_cross_domain
def enable_cors():
"""
钩子函数,处理请求路由之后需要做什么的事情
:return:
"""
pass
# response.headers['Access-Control-Allow-Origin'] = '*'
@get('/favicon.ico')
def favicon():
return ''
@get('/log/')
def callback():
pass
# """输出日志记录"""
# if not const.IS_ONLINE:
# return static_file('info.log', root=log_path)
@error(500)
def miss(code):
# ssh
# 错误页面,一般来说,可以在网站制定一个404的HTML页面,然后用return template('404')去访问404这个页面
return web_helper.return_msg(500, '服务器系统故障')
@error(404)
def miss(code):
# 错误页面,一般来说,可以在网站制定一个404的HTML页面,然后用return template('404')去访问404这个页面
return web_helper.return_msg(404, '接口不存在')
# 函数主入口
if __name__ == '__main__':
# 初始化全局的redis缓存处理工具
cache_helper.set_redis(redis_config.REDIS)
app_argv = SessionMiddleware(default_app(), session_opts)
run(app=app_argv, host='127.0.0.1', port=8189, debug=True, reloader=True)
else:
# 初始化全局的redis缓存处理工具
cache_helper.set_redis(redis_config.REDIS)
# 初始化email发送参数
# mail_helper.set_mail(const.MAIL)
application = SessionMiddleware(default_app(), session_opts)
@post('/api/user/login/')
@get('/api/user/login/')
def callback():
"""获取短链接生成页面html"""
return web_helper.return_msg(200, '登入成功!')
============================
2018年12月16日 13:55:29--跨域问题的新总结
=======================
解决问题的方式如下注释:
加上以下代码即可:
allow_headers = 'Referer, Accept, Origin, User-Agent,X-Requested-With, Content-Type, X-File-Name'
response.headers['Access-Control-Allow-Headers'] = allow_headers
image.png
网友评论