Nodejs http (三)

ajax跨域解决方案

  1. jsonp     2. cors   3. iframe   4. websocket   5. window.name   6. nginx

新建index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<!-- 跨域 域名、协议、端口号 其中任何一个不满足都是跨域-->
<script>
// axios 是基于 xhr 来实现 支持promise, axios自带拦截器
// fetch 不是基于xhr的,发请求就只有一个fetch请求,并且api很底层,不能终止fetch,因为它是一个promise

fetch('http://localhost:3000/api',{
method: 'get',
}).then(res=>{
return res.json();
// res.json表示将1.core.js服务器返回的结果转化成json; return res.json() 返回的是一个promise 走下面这个then
}).then(json=>{
console.log('打印:', json);
})
</script>
</body>
</html>

1.core.js

1
2
3
4
5
6
7
8
9
const http = require('http');

http.createServer((req,res)=>{
if(req.url === '/api'){
res.end(JSON.stringify({name: 'jf'}));
}
}).listen(3000);
// 当前为服务器端 启动服务 nodemon 1.core.js
// 客户端 Open with Live Serve index.html 如下图报跨域错误

配置简单跨域设置

1
2
3
4
5
6
7
8
9
// 1.core.js
const http = require('http');
http.createServer((req,res)=>{
res.setHeader('Access-Control-Allow-Origin','*');
if(req.url === '/api'){
res.end(JSON.stringify({name: 'jf'}));
}
}).listen(3000);
// 浏览器访问index.html 打印: {name: "jf"}

OPTIONS请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!--index.html-->
<script>
// 如果用户发送了OPTIONS请求,就是试探能不能访问服务器
fetch('http://localhost:3000/api',{
method: 'get',
headers:{
token: 'xxxx...', // 自定义header
}
}).then(res=>{
return res.json();
}).then(json=>{
console.log('打印:', json);
})
// 自定义header加上任何请求(get、post...),都是复杂请求 运行
</script>

允许访问,但是header需要设置一下,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
// 1.core.js
const http = require('http');
http.createServer((req,res)=>{
res.setHeader('Access-Control-Allow-Origin','*');
// 如果发送的是其他header 需要这里进行设置允许
res.setHeader('Access-Control-Allow-Headers', 'token,...');
if(req.method === 'OPTIONS'){
return res.end();
}
if(req.url === '/api'){
res.end(JSON.stringify({name: 'jf'}));
}
}).listen(3000);

设置了header里面的token之后

第一次是OPTIONS,发送了一个试探请求

第二次是GET,能够获取到res返回的值


发送复杂请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!--index.html-->
<script>
fetch('http://localhost:3000/api',{
method: 'delete', // 发送的是复杂请求
headers:{
token: 'xxxx',
}
}).then(res=>{
return res.json();
}).then(json=>{
console.log('打印:', json);
})

</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 1.core.js
const http = require('http');
http.createServer((req,res)=>{
res.setHeader('Access-Control-Allow-Origin','*');
res.setHeader('Access-Control-Allow-Headers', 'token,xxx');
// 我允许哪个方法来访问我 默认是支持get、post的
res.setHeader('Access-Control-Allow-Methods', 'PUT,DELETE');
// 30分钟 发一次options prefight 这个叫预检请求
res.setHeader('Access-Control-Max-Age', '1800');
if(req.method === 'OPTIONS'){
return res.end();
}
if(req.url === '/api'){
res.end(JSON.stringify({name: 'jf'}));
}
}).listen(3000);

设置Cookie

http 无状态的 没法记住状态 一般会借助cookie 通过服务器设置cookie 每次请求的时候会带上cookie

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!--index.html-->
<script>
// 设置cookie
// 默认情况下 cookie是不允许跨域设置的
fetch('http://localhost:3000/api',{
method: 'delete',
headers:{
token: 'xxxx',
},
credentials: 'include', // 这里可以查看mdn fetch默认不会携带或接受cookie
}).then(res=>{
return res.json();
}).then(json=>{
console.log('打印:', json);
})
</script>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 1.core.js
const http = require('http');
http.createServer((req,res)=>{
console.log(res.headers);
// res.setHeader('Access-Control-Allow-Origin','*');
// 指访问的源 谁访问我就是指谁 不能写* 但是表示所有人都可以访问我
res.setHeader('Access-Control-Allow-Origin',req.headers.origin);
res.setHeader('Access-Control-Allow-Headers', 'token,xxx');
res.setHeader('Access-Control-Allow-Methods', 'PUT,DELETE');
res.setHeader('Access-Control-Max-Age', '1800');
// 允许客户端携带凭证
res.setHeader('Access-Control-Allow-Credentials', true);
if(req.method === 'OPTIONS'){
return res.end();
}
if(req.url === '/api'){
console.log('headers:', req.headers.cookie); // name=jf
res.setHeader('Set-Cookie', 'name=jf');
res.end(JSON.stringify({name: 'jf'}));
}
}).listen(3000);
// 图这里不能写* 1这里不能写*(line5) + 2服务器允许客户端携带凭着(line12) 这2点设置
// 服务端设置之后每次客户端请求以后都会带上 就可以知道是否登陆过

以上为ajax跨域相关的头设置

反向代理

nginx 反向代理 就是针对用户是透明的
webpack proxy 反向 代理接口 我访问的还是以前的接口 主要的功能就是缓存 cdn 也是一个反向代理,感觉用户访问的是主机,其实访问的是各个子代理站点 (缓存+反向代理)

webpack 它是如何实现反向代理的,核心就是创建代理服务器

从 2.proxy.js 服务器 去请求 5000.js 服务器,通过访问2.proxy网站去请求5000.js, 2.proxy相当于中间层

1
2
3
4
5
6
7
8
9
10
11
12
// 2.proxy.js
let http = require('http');
let httpProxy = require('http-proxy'); // 用法可以看npmjs上的http-proxy
var proxy = httpProxy.createProxyServer(); // 开启了一个服务

http.createServer((req,res)=>{
// http-proxy npmjs => 搜索=> http-proxy , 安装npm install http-proxy --save
// 这里进行服务的转发
proxy.web(req,res,{
target: 'http://localhost:5000'
})
}).listen(3000);

新建5000.js

1
2
3
4
5
6
// 5000.js
let http = require('http');

http.createServer((req,res)=>{
res.end('I am 5000 port');
}).listen(5000);

开启服务: 1、node 5000.js 2、nodemon 2.proxy , 访问端口 3、localhost:3000,浏览器打印出I am 5000 port

能干什么?

现在希望一个服务器上可以部署多个网站 nginx
如果我现在要部署2个网站
www.jf1.cn 那么默认访问这个端口是80
www.jf2.cn 那么默认访问这个端口也是80
中间会有一个代理机 proxy 如果是www.jf1.cn 会到3000端口上 , www.jf2.cn会到3001端口上 感觉访问的是80 其实被分配到了其他的端口上。
实行:拿到当前访问的域名,根据域名来访问

根据host不同返回不同的网站,主要依靠的就是反向代理

反向是针对浏览器透明 正向是针对服务器透明

302临时重定向

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 根据内核跳转页面 302 临时重定向
const http = require('http');

// 手机端 移动页面
// pc端
http.createServer((req,res)=>{
// 如果是手机端 跳转到百度 , 如果是pc端 跳转到知乎
// 浏览器pc端模式:User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36
// 浏览器手机端模式:User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1
let userAgent = req.headers['user-agent'];
if(userAgent.includes('iPhone')){
res.statusCode = 302;
res.setHeader('Location', 'http://www.baidu.com');
res.end(); // 结束当前服务 这样才会跳转到设置的这个网站
}else{
res.statusCode = 302;
res.setHeader('Location', 'http://www.zhihu.com');
res.end();
}
// 这就是常见的服务器重定向 redirect
}).listen(3000);

运行 nodemon 4.agent.js 浏览器访问 localhost:3000

多语言

根据客户端所支持的语言返回对应的结果
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
客户端可以自行配置语言 不同的语言组成不同的网站