草庐IT

漏了一个“/”导致的跨域错误(CORS)

magicduan--编程爱好者 2023-09-28 原文

在成功搭建好DRF(Django rest framework)的Blog的backend后,昨天开始搭建Vue3+axios+pinia+element_plus的前台服务.

开始一切顺利,到第一个axios的get处理的时候,出现了错误.

axios相关的代码如下:

加载vue-axios和axios模块

npm install --save vue-axios axios

axios初始化(main.ts)

app.use(VueAxios, axios);
axios.defaults.baseURL = "http://localhost:8000/api";
//axios.defaults.headers.common['Access-Control-Allow-Origin'] = '*';
// axios.defaults.headers.common['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS';
//axios.defaults.headers.common['Access-Control-Allow-Headers'] = 'X-Requested-With,content-type';
//axios.defaults.headers.common['Content-Type'] = 'application/x-www-form-urlencoded';

app.provide('axios',app.config.globalProperties.axios)

 

axios取数据

在Pinia的Store中调用axios.get方法取得Backend端的Tag数据

export const useBlogData = defineStore("blogData",()=>{

    const axios:any = inject('axios');
    const tagsMenu = ref([])
    axios.get('/tags').then((response:{data:any})=>{
        tagsMenu.value = response.data.results;

    })

    return {tagsMenu}
})

目前的代码不严谨,没有进行错误处理.

出现跨域错误(CORS)

在Chrome的开发者模式下可以看到,报告Cors错误(CORS policy: No ‘Access-Control-Allow-Orign’ header is present on requested resource.

 发现错误后,急急慢慢去Google解决方案, 了解CORS的出错的原因以及可能的解决方案,

CORS跨域错误的原因

MDN上有文章详细说明了CORS出错的原因以及Client Server端的请求与应答之间的关系.https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS

简单的来说,我们的backend与frontend服务是分开的, Browser在执行Vue相关的处理的时候,回交叉访问不同的服务器,这样对于服务器来说可能会出现安全漏洞,所以会对这种请求进行拒绝操作.

关于CORS的中文的说明在Google云上有一篇文章说明https://cloud.google.com/storage/docs/cross-origin?hl=zh-cn, 我觉得还是MDN上讲解的更透彻.

CORS跨域错误的解决方案

在Google、StackOverflow上各种查询最终得出应该是两种解决方案:

Backend Server端的解决方案

Django提供了Backend Server端的解决方案,在前面的文章中已经提到过处理方法:

参考Django的CORS Header模块说明 https://pypi.org/project/django-cors-headers/

安装django-cors-headers, 修改setting.py, 其中需要注意的是MiddleWare相关的修改

MIDDLEWARE = [
    ...,
    "corsheaders.middleware.CorsMiddleware",
    "django.middleware.common.CommonMiddleware",
    ...,
]

corsheaders.middleware.CorsMiddleware的位置尽量向上,要在这个CommonMiddleware前面,否则也可能会出现CORS错误.

我的Backend端一直有这样的处理,检查代码,加入各种奇怪的配置,还是继续出错,苦恼很长时间.

Frontend Sever的解决方案

Frontend Server的解决方案就是在Frontend Server上设置Proxy, 将Vue的axios发起的get请求不直接发给Backend Server,发给Frontend, Frontend通过Proxy的配置转给Backend Server,从而避免了CORS的问题.

我的开发环境使用的是Vite, Google等上面有说修改vue.config.ts的,这个主要是面向Vue-CLI的,在Vite上修改的vite.config.ts

  server:{
    port:8080,
    proxy:{
      '/api':'http://127.0.0.1:8000'
    }
  },

加入proxy代理, 如上所示我的backend端的rest api的url是http://127.0..0.1:8000/api ,加入上述处理后 Frontend对应的http://localhost:8080/api上的请求会通过proxy转移到backend上

在axios的处理中,将面向backend处理baseurl设置为frontend上

axios.defaults.baseURL = "http://localhost:8080/api";

通过Frontend Server的解决方案可以成功解决目前碰见的CORS问题.

为什么Backend Server端的解决方案没有解决问题呢?

虽然通过Frontend Server的解决方案绕过了CORS错误,但是为什么Backend Server端的解决方案就是不行呢? 

Google、Stackoverflow给出了在http的header上加Access-Control-Allow-Origin的解题过程.

我在代码中加入headers相关的处理

axios.defaults.baseURL = "http://localhost:8000/api";
axios.defaults.headers.common['Access-Control-Allow-Origin'] = '*';

Chrome上的错误出现了新的情况:变成 access-control-allow-orign is not allowed by Access-Control-Headers的错误

在Chrome 网络中可以看见多了一个axios的请求成功了, axios发了一个preflight的请求去Backend预检测是否可以跨域请求

发现preflight请求成功了,我以为自己离解决问题近了一步,现在反思起了其实是退步了. 之后一直陷在这个地方找不到原因,各种Server端的配置,Frontend端的配置都不能成功.

在Stackoverflow上发现有人说问题就是结尾少了一个“/”我在axios的get请求“/tags”加入“/tags/”, 仍然还是出错.一度错过了这个问题的解决方案.

解决问题

折腾一晚上睡觉起了,再仔细的看MDN中的文章, 文章中说对于Simple Request(get、post、put、delete)的请求是不需要发送preflight请求的.现在看这个错误的意思就是access-control-allow-orgin这个header字段不被Backend Server支持,Backend拒绝了访问. 看不到解决方案决定回到起点,将header相关的处理去掉,将axios的代码回归到

axios.defaults.baseURL = "http://localhost:8000/api";
//axios.defaults.headers.common['Access-Control-Allow-Origin'] = '*';

通过curl -i -L查看请求的结果,发现Backend端其实已经取得了tags数据,并返回给Broswer,但是结果确被重定向了,会出现301错误

这时候想起看过的关于请求结尾需要加“/”的处理,想明白了可能就是这个“/”导致的错误.在axios的get请求中将“/tags”,修改为“/tags/”.问题得到解决.

修改代码 

export const useBlogData = defineStore("blogData",()=>{

    const axios:any = inject('axios');
    const tagsMenu = ref([])
    axios.get('/tags/').then((response:{data:any})=>{
        tagsMenu.value = response.data.results;

    })

    return {tagsMenu}
})

最终的解决方案: Backend的cors header模块 + “/”解决问题.

还有一个需要注意的地方是,在每次修改代码后,最好是将之前的页面关掉,重开避免Cache引起的干扰.

 

 

有关漏了一个“/”导致的跨域错误(CORS)的更多相关文章

  1. ruby-on-rails - Rails 常用字符串(用于通知和错误信息等) - 2

    大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje

  2. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

    使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

  3. ruby-on-rails - Rails - 一个 View 中的多个模型 - 2

    我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何

  4. ruby-on-rails - 渲染另一个 Controller 的 View - 2

    我想要做的是有2个不同的Controller,client和test_client。客户端Controller已经构建,我想创建一个test_clientController,我可以使用它来玩弄客户端的UI并根据需要进行调整。我主要是想绕过我在客户端中内置的验证及其对加载数据的管理Controller的依赖。所以我希望test_clientController加载示例数据集,然后呈现客户端Controller的索引View,以便我可以调整客户端UI。就是这样。我在test_clients索引方法中试过这个:classTestClientdefindexrender:template=>

  5. ruby-on-rails - 如果 Object::try 被发送到一个 nil 对象,为什么它会起作用? - 2

    如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象

  6. ruby - 为什么 SecureRandom.uuid 创建一个唯一的字符串? - 2

    关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion为什么SecureRandom.uuid创建一个唯一的字符串?SecureRandom.uuid#=>"35cb4e30-54e1-49f9-b5ce-4134799eb2c0"SecureRandom.uuid方法创建的字符串从不重复?

  7. ruby-on-rails - 迷你测试错误 : "NameError: uninitialized constant" - 2

    我遵循MichaelHartl的“RubyonRails教程:学习Web开发”,并创建了检查用户名和电子邮件长度有效性的测试(名称最多50个字符,电子邮件最多255个字符)。test/helpers/application_helper_test.rb的内容是:require'test_helper'classApplicationHelperTest在运行bundleexecraketest时,所有测试都通过了,但我看到以下消息在最后被标记为错误:ERROR["test_full_title_helper",ApplicationHelperTest,1.820016791]test

  8. ruby-on-rails - 如何在 Rails View 上显示错误消息? - 2

    我是rails的新手,想在form字段上应用验证。myviewsnew.html.erb.....模拟.rbclassSimulation{:in=>1..25,:message=>'Therowmustbebetween1and25'}end模拟Controller.rbclassSimulationsController我想检查模型类中row字段的整数范围,如果不在范围内则返回错误信息。我可以检查上面代码的范围,但无法返回错误消息提前致谢 最佳答案 关键是您使用的是模型表单,一种显示ActiveRecord模型实例属性的表单。c

  9. 使用 ACL 调用 upload_file 时出现 Ruby S3 "Access Denied"错误 - 2

    我正在尝试编写一个将文件上传到AWS并公开该文件的Ruby脚本。我做了以下事情:s3=Aws::S3::Resource.new(credentials:Aws::Credentials.new(KEY,SECRET),region:'us-west-2')obj=s3.bucket('stg-db').object('key')obj.upload_file(filename)这似乎工作正常,除了该文件不是公开可用的,而且我无法获得它的公共(public)URL。但是当我登录到S3时,我可以正常查看我的文件。为了使其公开可用,我将最后一行更改为obj.upload_file(file

  10. ruby-on-rails - 错误 : Error installing pg: ERROR: Failed to build gem native extension - 2

    我克隆了一个rails仓库,我现在正尝试捆绑安装背景:OSXElCapitanruby2.2.3p173(2015-08-18修订版51636)[x86_64-darwin15]rails-v在您的Gemfile中列出的或native可用的任何gem源中找不到gem'pg(>=0)ruby​​'。运行bundleinstall以安装缺少的gem。bundleinstallFetchinggemmetadatafromhttps://rubygems.org/............Fetchingversionmetadatafromhttps://rubygems.org/...Fe

随机推荐