最早由netscape公司提出,是浏览器的一种安全策略
前端请求页面会出现跨域问题
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<button>发送button>
<script>
let btn = document.getElementsByTagName('button')[0];
btn.addEventListener('click', () => {
let xml = new XMLHttpRequest();
xml.open('get', 'http://127.0.0.1:2200', true);
xml.timeout = 2000;
xml.addEventListener('timeout', () => {
xml.abort();
console.error('请求超时');
});
xml.addEventListener('error', () => {
console.error('请求错误');
});
xml.send(null);
xml.addEventListener('readystatechange', () => {
if (xml.readyState === 4) {
if (xml.status >= 200 && xml.status < 300 || xml === 304) {
console.log(xml.responseText);
}
}
});
});
script>
body>
html>
后端
const http = require('http');
const server = http.createServer();
server.on('request', (request, response) => {
if (request.method === 'get') {
response.end('get');
} else {
response.end('post');
}
});
server.listen(2200, err => {
err ? console.log('服务启动失败') : console.log('服务启动成功');
});
控制台报错:
Access to XMLHttpRequest at ‘http://127.0.0.1:2200/’ from origin ‘null’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.
jsonp
处理
原理
利用javascript标签请求不受同源协议影响的原理,
通过在客户端中创建script标签,在对应src中插入请求路径并携带执行函数的函数名参数到后端
在后端拼接一个函数执行的字符串,返回前端
在前端接收并执行
这样就可以拿到后端的数据了
<body>
<button>发送POSTbutton>
<script type="text/javascript">
// 创建用于接收后端参数的方法
function getHero(data) {
data.forEach(element => {
console.log(element.uname);
});
};
script>
<script>
// 创建JSONP方法
function myJsonp({
url,
methodName,
}) {
// 创建script
let script = document.createElement('script');
// 拼接路径,再拼接传递参数(函数名)
script.setAttribute('src', url + '?callback=' + methodName);
// 在头部插入script
document.head.appendChild(script);
// 使用后移除script标签 避免过多的script标签
document.head.removeChild(script);
}
// 调用jsonp
// 传入对应路径和方法名
myJsonp({
url: 'http://localhost:2200/getHero',
methodName: 'getHero'
});
script>
body>
后端
const http = require('http');
const url = require('url');
const server = http.createServer();
server.on('request', (request, response) => {
if (request.method === 'GET') {
let prop = url.parse(request.url, true);
let obj = [{ uname: 'Tom' }, { uname: 'Boby' }, { uname: 'anla' }];
response.end(prop.query.callback + '(' + `${JSON.stringify(obj)}` + ');');
} else {
response.end('post');
}
});
server.listen(2200, err => {
err ? console.log('服务启动失败') : console.log('服务启动成功');
});
CORS
1 CORS(跨域资源共享)
CORS基本思想:使用自定义的HTTP头部让浏览器和服务器通信
2 简单请求与非简单请求:
浏览器将CORS请求分成两类:简单请求和非简单请求。只要同时满足以下两大条件,就属于简单请求。
请求方法是以下三种方法之一:
HEAD
GET
POST
HTTP的头信息不超出以下几种字段:
> Accept
> Accept-Language
> Content-Language
> Last-Event-ID
> Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
对于简单请求,浏览器直接发出CORS请求。具体来说,就是在头信息之中,增加一个Origin字段。
非简单请求是那种对服务器有特殊要求的请求,比如请求方法是PUT或DELETE,
或者Content-Type字段的类型是application/json。非简单请求的CORS请求,会在正式通信之前,
增加一次HTTP查询请求,称为"预检"请求(preflight)。
CORS字段:
Access-Control-Allow-Origin
必须。值为允许域名的地址或者是一个*表示允许所有域名地址的请求。
Access-Control-Allow-Credentials
可选。一个布尔值,表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中。
设为true,即表示服务器明确许可,Cookie可以包含在请求中,一起发给服务器。
这个值也只能设为true,如果服务器不要浏览器发送Cookie,删除该字段即可。
Access-Control-Request-Method
必须,指明允许的CORS请求用到HTTP方法。GET, POST, PUT, PATCH, DELETE ···
Access-Control-Request-Headers
该字段可选。该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段。
前端并无太大变化,主要后端设置
const http = require('http');
const server = http.createServer();
server.on('request', (request, response) => {
// 设置跨域允许的域---只允许来自http://127.0.0.1:5500(挂起静态页面的服务地址,这里是我是用插件挂起的服务)的请求
response.setHeader('Access-Control-Allow-Origin', 'http://127.0.0.1:5500');
// 允许来自所有域的请求
// response.setHeader('Access-Control-Allow-Origin', '*');
// 设置允许的请求方法
response.setHeader('Access-Control-Request-Methods', 'GET', 'post');
if (request.method.toLocaleLowerCase() === 'get') {
response.end('get');
} else {
response.end('post');
}
});
server.listen(2200, err => {
err ? console.log('服务启动失败') : console.log('服务启动成功');
});
设置代理服务器
代理服务器
const http = require('http');
const server = http.createServer();
/* 简单的代理服务器 */
server.on('request', (request, response) => {
// 请求后立即重定向到新的服务器对应地址
response.writeHead(302, { 'Location': 'http://127.0.0.1:4400/' });
// 终止请求
response.end();
/* 利用服务器之间的请求不会产生跨域问题的原理 */
});
server.listen(2200, err => {
err ? console.log('代理服务启动失败') : console.log('代理服务启动成功');
});
资源服务器
const http = require('http');
const server = http.createServer();
/* 目标服务器 */
server.on('request', (request, response) => {
if (request.method.toLocaleLowerCase() === 'get') {
response.end('get');
} else {
response.end('post');
}
});
server.listen(4400, err => {
err ? console.log('服务启动失败') : console.log('服务启动成功');
});