前端跨域的几种解决办法

   关于前端跨域问题用的最多的应该是cors,关于jsonp主要用于get请求,前端代理也仅适用于开发阶段,上线阶段还是要后台配置跨域问题。

   今天主要介绍下面三种,会配合nodejs一起呈现

1.jsonp (主要用于get请求,原理是利用script标签可以请求不同域)

  jsonp需要前后端配合,约定回调函数的名字,我是在3000的端口下请求3001的服务器,下面直接看代码

前端(index.html)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<ul id="name">
</ul>
<script>

    request()

    function request() {
        var
            js = document.createElement('script'),
            head = document.getElementsByTagName('head')[0];
        js.src = 'http://localhost:3001/api/users?callback=userAdd';
        head.appendChild(js);
    }

    function userAdd(data) {
        document.getElementById("name").innerHTML = data.map((item) => {
            console.log(item)
            return `<li>${item.name}</li>`
        }).join('')
    }
</script>
</body>
</html>

nodejs(3001服务器代码)

const http = require("http")
const fs = require('fs')
const qs = require('querystring')
const URL = require('url')
const users = [
    {
        name: 'jackie',
        age: 27
    },
    {
        name: 'Tom',
        age: 20
    }

]
const server = http.createServer((req, res) => {
    const {url, method} = req;
    const{callback} = URL.parse(req.url,true).query//需要使用nodejs的url模块序列化参数
    console.log(callback)
    if (callback) {//判断传递参数的回调

        res.writeHead(200, {'Content-Type': 'text/javascript'})
        res.end(callback+`(${JSON.stringify(users)})`);//把获取的函数名和要传递的数据拼接返回给前端
        //res.end(callback+"("+JSON.stringify(users)+")");
    }
    else {//如果没有传递参数的回调处理
        res.writeHead(200, {'Content-Type': 'application/json'})
        res.end(JSON.stringify(users))
    }
 
})
server.listen(3001)

(3000服务器代码) 

const http = require("http")
const fs = require('fs')
const qs = require('querystring')
const server = http.createServer((req, res) => {
    const {url, method} = req;
    if (url === '/' && method === 'GET') {
    console.log('11')
    fs.readFile('./index.html', (err, data) => {
        if(err) {
            res.writeHead(500, {'Content-Type': 'text/plain'})
            res.end('server error')
            return
        }
        res.writeHead(200, {'Content-Type': 'text/html'})
    res.end(data)
    })
})
server.listen(3000)

2.cors

在说到cors解决跨域之前我们有必要来了解一下简单请求和非简单请求

     满足以下两大条件,就属于简单请求,那么不满足的就是非简单请求了

(1) 请求方法是以下三种方法之一:
    HEAD
    GET
    POST
(2)HTTP的头信息不超出以下几种字段:   
    Accept
    Accept-Language
    Content-Language
    Last-Event-ID
    post请求的Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

  先来说简单请求的跨域解决,通过3001的服务器访问3000的接口,先上代码
  前端(index.html)(这是一个简单请求,post+Content-Type(application/x-www-form-urlencoded))

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="http://localhost:3000/api/users" method="post">
    <input type="text" name="name">
    <input type="number" name="age">
    <input type="submit" value="新增用户">
</form>

<ul id="name">

</ul>
</body>
</html>

nodejs(3000端口)

const http = require("http")
const fs = require('fs')
const qs = require('querystring')

const users = [
    {
        name: 'jackie',
        age: 27
    },
    {
        name: 'Tom',
        age: 20
    }

]
const server = http.createServer((req, res) => {
    const {url, method} = req;
console.log(url,method)
if (url === '/' && method === 'GET') {
    console.log('11')
    fs.readFile('./index.html', (err, data) => {
        if(err) {
            res.writeHead(500, {'Content-Type': 'text/plain'})
            res.end('server error')
            return
        }
        res.writeHead(200, {'Content-Type': 'text/html'})
    res.end(data)
})

} else if (url === '/api/users' && method === 'GET') {
    console.log('22')
    //用writeHead再加setHeader不行,为什么请去查阅文档
    //res.writeHead(200, {'Content-Type': 'application/json'})
    res.setHeader('Content-Type', 'application/json')
    //简单请求加cors
    res.setHeader('Access-Control-Allow-Origin','http://localhost:3001');
    res.setHeader("Access-Control-Allow-Credentials",true);

    //res.setHeader('Access-Control-Allow-Origin','http://localhost:3001')
    res.end(JSON.stringify(users))
} else if (url === '/api/users' && method === 'POST') {
    //接受请求参数
    let body = []
    req.on('data', (chunk) => {
        console.log(chunk)
    body.push(chunk);
}).
    on('end', () => {
        //数据接收完毕之后把body转换为完整的buffer
        body = Buffer.concat(body).toString();
    const user = qs.parse(body)
    users.push(user);
    res.writeHead(200, {'Content-Type': 'text/plain'})
    res.end('add success!')
})

}else if(method=='OPTIONS' && url=='/api/users'){
    console.log('444')
    res.writeHead(200,{
        "Access-Control-Allow-Origin":"http://localhost:3001",
        "Access-Control-Allow-Headers":"X-Token,content-type",
        "Access-Control-Allow-Methods":"GET,POST,PUT",
        "Access-Control-Allow-Credentials":"true",
    })
    res.end();
}

})
server.listen(3000)

   (3001端口)

const http = require("http")
const fs = require('fs')
const qs = require('querystring')
const URL = require('url')
const server = http.createServer((req, res) => {
    const {url, method} = req;
    if (url === '/' && method === 'GET') {
        fs.readFile('./index.html', (err, data) => {
            if (err) {
                res.writeHead(500, {'Content-Type': 'text/plain'})
                res.end('server error')
                return
            }
            res.writeHead(200, {'Content-Type': 'text/html'})
            res.end(data)
        })
    } 
})
server.listen(3001)

效果图(新增用户成功)

 

非简单请求会先发一个options请求

在node后台加个判断:

else if(method=='OPTIONS' && url=='/api/users'){
    console.log('444')
    res.writeHead(200,{
        "Access-Control-Allow-Origin":"http://localhost:3001",
        "Access-Control-Allow-Headers":"X-Token,content-type",
        "Access-Control-Allow-Methods":"GET,POST,PUT",
        "Access-Control-Allow-Credentials":"true",
    })
    res.end();
}

前端在3001下请求3000的接口

axios.post("http://localhost:3000/api/users",{
        header:{
            'Content-Type':'application/json'
        }
    })
        .then(res=>res.data).then(users=>{
        console.log(users);
        document.getElementById("name").innerHTML=users.map((item)=>{
            console.log(item)
            return `<li>${item.name}</li>`
        }).join('')
    })

效果图

 

 

3.代理

我用的vue-cli3.0,配置vue.config.js的 devServer

devServer: {
        proxy: {
            '/api': {//代理api
                target: "http://ip:port",//服务器api地址
                changeOrigin: true,//是否跨域
                ws: true, // proxy websockets
                pathRewrite: {//重写路径
                    "^/api": ''
                }
            }
        }
    }

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值