React跨域
解决方案在二,想简单了解下跨域的可读一。
我们由于项目需要经常会需要对不同域名、不同子域的网站接口发起请求,有时甚至是对于同一域名的不同端口发起请求,此时我们经常看到以下报错:
Access to XMLHttpRequest at 'xxx' from origin 'xxx' has been blocked by CORS
policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
是的,错误的原因就是你跨域了。刚碰到跨域问题时在网上寻找了大半天,不是报错就是无法跨域转发。最后才发现是react新版本更新了相关规则的缘故。记述下来供大家参考。
一、为什么会有跨域问题?
看到网上举的一个形象例子,先设想下,如果允许跨域,那么黑衣人是不是可以在自己的网页上把请求转发给其他网站?例如,黑衣人在自己的页面设计了一个跨域请求到某钱堆的网址,当用户访问黑衣人网址时,浏览器按照黑衣人设计去访问了钱堆(还携带了用户在钱堆那儿的cookie)......之后,之后警察叔叔们又要加班了。还有诸如此类许多安全隐患。所以后来的浏览器都开始实行同源策略。
同源策略,其实就是只允许相同协议+域名+端口号(如存在)的HTTP请求互相访问。这么理解其实就够了。关于跨域资源共享标准( cross-origin sharing standard )CORS的详细内容,大家可参考这篇文章:链接
本文主要讲React框架下怎么解决跨域问题。
二、怎么解决跨域问题?
这里我给出两种React的跨域解决方案(React16.9亲测可行),第一种比较实用,第二种需要服务端协调。
1.http-proxy-middleware
网上一大片说直接在package.json中配置proxy的,这个方法已经失效很久了。官方给出的新版本解决方案需要借助http-proxy-middleware这个包:
1. npm install http-proxy-middleware
2. src目录下创建setupProxy.js,配置如下:
const proxy = require('http-proxy-middleware')
module.exports = function (app) {
// proxy第一个参数为要代理的路由
// 第二参数中target为代理后的请求网址,changeOrigin是否改变请求头,其他参数请看官网
app.use(proxy('/cityjson', {
target: 'http://pv.sohu.com',
changeOrigin: true
}))
}
3. 测试一下:
//页面代码:
import React,{ useEffect,useState } from 'react'
import axios from 'axios';
const App = function () {
const [ip,setIp] = useState()
useEffect(()=>{
(async function f(){
let res = await axios.get('/cityjson') //这里使用搜狐的ip信息查询接口
setIp(res.data.toString())
})()
},[])
return (
<h1>获取的IP信息:{ip}</h1>
)
}
export default App
成功获取!
2.借助服务端配置
其实有过服务端开发经验的同学应该一眼就能看出,上面配置setupProxy.js的样子像极了node服务端使用中间件的样子。再看看,http-proxy-middleware,middleware就是中间件的意思。
好了,大概知道了,其实新版本的更新就是想把跨域请求放在服务端去做,而削弱前端跨域的能力(大概是为了安全吧,个人臆想)
在服务端配置的话,只需要在服务端中间件文件里插入http-proxy-middleware即可。express框架和上面的配置基本一样,koa的话参考以下这样:
const Koa = require('koa')
const proxy = require('http-proxy-middleware')
const app = new Koa()
//跨域代理
app.use(async (ctx, next) => {
if(ctx.url.startsWith('/cityjson')) {
ctx.respond = false
return proxy({
target: 'http://pv.sohu.com', // 服务器地址
changeOrigin: true,
})(ctx.req, ctx.res, next)
}
return next()
})
......