最近在学习nodeJS 的内容,用 koa2 搭建了一个项目。在进行前后端串接的时候遇到了跨越的问题。
跨域的解决有两个方向:
其一,前端设置api代理
// vue.config.js
devServer: {
proxy: {
'/api': {
target: '',
changeOrigin: true, // 允许websockets跨域
ws: true,
pathRewrite: {
'^/api': ''
}
}
} // 代理转发配置,用于调试环境
}
关于 vue.config.js
更多配置可查看:关于 Vue CLI 4.0 的 vue.config.js 基本配置范例(jquery、图片压缩、CSS modules)
其二,后端设置允许跨域。(本文所用的就是这个)
关于后端的跨域配置基本有两种。
使用原生的 koa2 代码配置;
app.use(async (ctx, next) => {
ctx.set('Access-Control-Allow-Origin', '*');
ctx.set('Access-Control-Allow-Headers', 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild');
ctx.set('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS');
if (ctx.method == 'OPTIONS') {
ctx.body = 200;
} else {
await next();
}
})
使用中间件 koa2-cors
(推荐)
app.use(
cors({
origin: function (ctx) { //设置允许来自指定域名请求
// if (ctx.url === '/test') {
// return '*'; // 允许来自所有域名请求
// }
return ctx.header.origin; //只允许http://localhost:8080这个域名的请求
},
maxAge: 5, //指定本次预检请求的有效期,单位为秒。
credentials: true, //是否允许发送Cookie
allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], //设置所允许的HTTP请求方法
allowHeaders: ['Content-Type', 'Authorization', 'Accept'], //设置服务器支持的所有头信息字段
exposeHeaders: ['WWW-Authenticate', 'Server-Authorization'] //设置获取其他自定义字段
})
);
但是呢!依照各位大佬的方法,在koa2的app.js后面添加相应的配置。然而这配置就是一直不生效。
配置如下:
// app.js (app.js 是 koa2-generator 生成的)
const Koa = require('koa')
const app = new Koa()
const views = require('koa-views')
const json = require('koa-json')
const onerror = require('koa-onerror')
const bodyparser = require('koa-bodyparser')
const logger = require('koa-logger')
const index = require('./routes/index')
const users = require('./routes/users')
const person = require('./routes/person')
const cors = require('koa2-cors')
// error handler
onerror(app)
// middlewares
app.use(bodyparser({
enableTypes: ['json', 'form', 'text']
}))
app.use(json())
app.use(logger())
app.use(require('koa-static')(__dirname + '/public'))
app.use(views(__dirname + '/views', {
extension: 'ejs'
}))
// logger
app.use(async (ctx, next) => {
const start = new Date()
await next();
const ms = new Date() - start
console.log(`${ctx.method} ${ctx.url} - ${ms}ms`)
})
// routes 路由配置
app.use(index.routes(), index.allowedMethods())
app.use(users.routes(), users.allowedMethods())
app.use(person.routes(), person.allowedMethods())
// error-handling
app.on('error', (err, ctx) => {
console.error('server error', err, ctx)
});
// 配置跨域
app.use(
cors({
origin: function (ctx) { //设置允许来自指定域名请求
// if (ctx.url === '/test') {
// return '*'; // 允许来自所有域名请求
// }
return ctx.header.origin; //只允许http://localhost:8080这个域名的请求
},
maxAge: 5, //指定本次预检请求的有效期,单位为秒。
credentials: true, //是否允许发送Cookie
allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], //设置所允许的HTTP请求方法
allowHeaders: ['Content-Type', 'Authorization', 'Accept'], //设置服务器支持的所有头信息字段
exposeHeaders: ['WWW-Authenticate', 'Server-Authorization'] //设置获取其他自定义字段
})
);
module.exports = app
经过多次测试之后,我悲催的发现:根本不是跨域配置出错的问题,而是跨域配置代码放置的问题。我将配置代码移到routes
配置前面就可以。
仔细一想,跨域是为routes
定义的api而配置的。确实应该放在前面。因为 js 代码是从上到下执行的。当代码运行道app,js
的 route
入口配置时,自然会跳转到对应的route
文件。如果把跨域的配置代码放到route
入口配置后面,肯定是不生效的。所以,必须要把跨域配置的代码段移动到route
入口配置的前面。
修正后的 代码如下:
const Koa = require('koa')
const app = new Koa()
const views = require('koa-views')
const json = require('koa-json')
const onerror = require('koa-onerror')
const bodyparser = require('koa-bodyparser')
const logger = require('koa-logger')
const index = require('./routes/index')
const users = require('./routes/users')
const person = require('./routes/person')
const cors = require('koa2-cors')
// error handler
onerror(app)
// middlewares
app.use(bodyparser({
enableTypes: ['json', 'form', 'text']
}))
app.use(json())
app.use(logger())
app.use(require('koa-static')(__dirname + '/public'))
app.use(views(__dirname + '/views', {
extension: 'ejs'
}))
// 配置跨域
app.use(
cors({
origin: function (ctx) { //设置允许来自指定域名请求
// if (ctx.url === '/test') {
// return '*'; // 允许来自所有域名请求
// }
return ctx.header.origin; //只允许http://localhost:8080这个域名的请求
},
maxAge: 5, //指定本次预检请求的有效期,单位为秒。
credentials: true, //是否允许发送Cookie
allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], //设置所允许的HTTP请求方法
allowHeaders: ['Content-Type', 'Authorization', 'Accept'], //设置服务器支持的所有头信息字段
exposeHeaders: ['WWW-Authenticate', 'Server-Authorization'] //设置获取其他自定义字段
})
);
// logger
app.use(async (ctx, next) => {
const start = new Date()
await next();
const ms = new Date() - start
console.log(`${ctx.method} ${ctx.url} - ${ms}ms`)
})
// routes 路由配置
app.use(index.routes(), index.allowedMethods())
app.use(users.routes(), users.allowedMethods())
app.use(person.routes(), person.allowedMethods())
// error-handling
app.on('error', (err, ctx) => {
console.error('server error', err, ctx)
});
module.exports = app