面试官提问:为什么表单提交不会出现跨域

这是之前面试的时候面试官提问的一道面试题。

具体题目是:为什么表单提交不会出现跨域,而使用 Ajax 发送 post 请求时却会出现跨域的情况。

那什么情况下会出现跨域:

协议 + 端口 + 端口 三者只要有一个不一样,就会出现跨域。

那为什么表单能够跨域发送请求,而 Ajax 却不能发送跨域请求

  • 归根结底:跨域是为了阻止用户读取到另一个域名下的内容
  • 而 Ajax 可以获取响应,但浏览器认为这不安全,所以拦截了响应
  • 但是表单并不会获取新的内容,所以可以发起跨域请求。

前者是发送跨域请求给到后端,并不去接收服务器返回的信息

后者是发送跨域请求给到后端,并接收服务器返回的信息

那该如何解决跨域

#方法一:使用 JSONP

原理是利用<script>标签的跨域特性,可以不受限制地从其他域中加载资源

js 复制代码
function jsonp(options) {
    var script = document.createElement('script');
    
    // 参数处理
    var params = '';
    for (var attr in options.data) {
        params += '&' + attr + '=' + options.data[attr];
    } 
    
    // 设置回调函数
    var successCallback =  `successCallback`;
    window[successCallback] = options.success;
    
    script.src = options.url + '?callback=' + successCallback + params;
    document.body.appendChild(script);
}

代码解释

请求成功后,前端得执行回调函数,但 script 脚本是执行不到 success() 方法的。

这是因为 success() 方法 并不是 全局函数 ,所以需要将 success() 方法 改成全局函数

js 复制代码
var successCallback =  `successCallback`;
window[successCallback] = options.success;

并在请求参数的基础上,需要添加 callback 参数,值对应需要回调的函数名

js 复制代码
script.src = options.url + '?callback=' + successCallback + params;

使用

js 复制代码
var btn = document.getElementById('btn');
btn.addEventListener('click', function() {
    jsonp({
        url: 'http://localhost:3001/getUserInfo',
        data: { name: '浩浩' },
        success: function(data) {
            alert('UserInfo:' + JSON.stringify(data));
        }
    })
});

JSONP 优缺点

  • 简单兼容性好,可用于解决主流浏览器的跨域数据访问的问题
  • 仅支持get方法具有局限性,不安全可能会遭受 XSS 攻击

#方法二:CORS

CORS 是一个 W3C 标准,全称是"跨域资源共享"(Cross-origin resource sharing)。 CORS 需要浏览器和服务器同时支持。但是目前基本上浏览器都支持,所以我们只要保证服务器端服务器实现了 CORS 接口,就可以跨源通信。

后端解决跨域问题,就是在服务器端给响应添加头信息

Name Required Comments
Access-Control-Allow-Origin 必填 允许请求的域
Access-Control-Allow-Methods 必填 允许请求的方法
Access-Control-Allow-Headers 可选 预检请求后,告知发送请求需要有的头部
Access-Control-Allow-Credentials 可选 表示是否允许发送cookie,默认false;
Access-Control-Max-Age 可选 本次预检的有效期,单位:秒;

在 node 上处理

js 复制代码
// 方式一
const Koa = require('koa')
const app = new Koa()

app.all("*", (req, res, next) => {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "content-type");
    
    // 关键点
    next()
})
js 复制代码
// 方式二
const Koa = require('koa')
const app = new Koa()

app.all("*", (req, res, next) => {
    // 设置域名跨域
    res.header("Access-Control-Allow-Origin", "http://127.0.0.1");
    // 跨域允许的请求方式
    res.header("Access-Control-Allow-Headers", "DELETE,PUT,POST,GET,OPTIONS");
    
    // 关键点
    next()
})

在 Nginx 上处理

js 复制代码
location /example {
  add_header Access-Control-Allow-Origin *;
  add_header Access-Control-Allow-Methods *;
  # add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
}
相关推荐
brzhang4 分钟前
告别『上线裸奔』!一文带你配齐生产级 Web 应用的 10 大核心组件
前端·后端·架构
程序员Bears4 分钟前
深入理解CSS3:Flex/Grid布局、动画与媒体查询实战指南
前端·css3·媒体·visual studio code
David凉宸16 分钟前
凉宸推荐给大家的一些开源项目
前端
袋鱼不重18 分钟前
Cursor 最简易上手体验:谷歌浏览器插件开发3s搞定!
前端·后端·cursor
hyyyyy!18 分钟前
《从分遗产说起:JS 原型与继承详解》
前端·javascript·原型模式
竹苓19 分钟前
从一个想法到上线,一万字记录我开发浏览器插件的全过程
前端
小桥风满袖19 分钟前
Three.js-硬要自学系列19 (曲线颜色渐变、渐变插值、查看设置gltf顶点、山脉高度可视化)
前端·css·three.js
zayyo20 分钟前
Vue.js性能优化新思路:轻量级SSR方案深度解析
前端·面试·性能优化
北溟鱼鱼鱼20 分钟前
跨域解决方案
前端
六边形66621 分钟前
一文搞懂JavaScript 与 BOM、DOM、ECMAScript、Node.js的用处
前端·javascript·面试