天天看點

axios get怎麼還會顯示跨域_react+axios用node代了解決跨域

今天自己搭了個react架子,網上找了個公開的接口,結果發現跨域了。因為接口是别人的,我沒法讓别人在接口上處理跨域問題,而且這個接口是post請求方式,也沒發用jsop處理跨域。

一、前端處理跨域

1、利用proxy代理

特點:這種方式簡單易用,不受接口類型限制,get,post等都能支援,适用于與前後端分離的項目。

使用方式:

找到package.json檔案,在裡面加上 proxy:代理接口位址,重新啟動項目即可。

"proxy": "http://10.99.206.102:9992/api/v1"

axios get怎麼還會顯示跨域_react+axios用node代了解決跨域

proxy

需要注意的是,若使用本方法代理跨域,且開啟了全局配置的公共接口位址,一定記得将公共接口位址配置為空。我項目一般使用的axios,需要将這個全局配置改為空。axios.defaults.baseURL = ""

随便請求一個接口,看看接口是不是走的自己電腦的ip或者localhost,若不是就證明代理跨域沒成功,檢查下接口配置有沒有清理。

2、利用jsonp處理get請求

若隻是想處理單個get請求的跨域,直接使用jsonp方式即可。這個項目中基本沒用,有需要的話,自己百度看看怎麼操作的。

二、node代理跨域

總體思路,就是直接讓node去掉這個跨域的接口(因為伺服器端不存在跨域,是以node調用接口是沒毛病的),拿到結果。然後在node端抛出這個路由,前端調用這個接口就可以了。但是我的react是腳手架啟動的,并不是我寫的node啟動的,是以端口還是不一樣,這樣還是有跨域問題,這時候的跨域問題就很好解決了,在後端配置下cros就好了。

當然,這種方式比較麻煩,一般工作中背景直接處理跨域就可以了,不需要單獨再啟動node處理跨域。這裡就是記錄下node一個完整的調用過程,java處理跨域也是一樣開啟一個cros即可。

閑話不多說,我直接把代碼附上,然後把寫代碼過程中遇到的問題總結下。

我調用的公共接口是 圖靈機器人 裡的接口

接口位址:

我是直接用create-react-app搭建的項目,然後把src下面的目錄都删掉,自己建了兩個檔案,index.js和index.css

最終的檔案目錄結構如下:

axios get怎麼還會顯示跨域_react+axios用node代了解決跨域

檔案目錄

src/index.js檔案如下:

import React from 'react'

import ReactDOM from 'react-dom'

import axios from 'axios'

import './index.css'

class Layout extends React.Component{

constructor(){

super()

this.state={

content:'',

value:'zoey'

}

}

componentDidMount(){

let data1

axios.post('http://www.tuling123.com/openapi/api',{

info:'今天我最美',

userId:1234

}).then(data=>{

console.log(data)

data1 = data

})

this.setState({

content:data1

})

}

render(){

debugger

const obj = this.state.content

let one = []

for( var item in obj){

one.push( item=='text'? obj[item]:'')

}

return

我是頭部資訊

{one}

}

}

ReactDOM.render(

,

document.querySelector('#root')

)

這裡就會發現報錯

axios get怎麼還會顯示跨域_react+axios用node代了解決跨域

跨域

因為同源政策,導緻這裡跨域,我就開始搭建了個node伺服器,代碼如下:

建了個檔案夾server,裡面建立3個檔案server.js routes.js home.js

server/server.js的代碼:

const Koa= require('koa')

const app = new Koa()

const routes = require('./routes.js');

//路由

app.use(routes());

app.listen(3001,()=>{

console.log('port is running at 3001')

})

server/routes.js的代碼

const compose = require('koa-compose');

const Router = require('koa-router');

var router = new Router();

const Home = require('./home');

router.get('/api/index', Home.index)

// app.use(router.routes()).use(router.allowedMethods());

module.exports = (ctx, next) => compose([router.routes(), router.allowedMethods()]);

server/home.js的代碼:

const axios = require('axios')

class Home {

static async index(ctx,next){

const {info,userId} =ctx.request.query

const {data} = await axios.post('http://www.tuling123.com/openapi/api',{

key:'c9d1eb9811e648a49ece24b7cb1065e9',

info:info,

userId:userId

})

console.log(data)

ctx.body=data

}

}

module.exports = Home

然後啟動這個server,為了友善我就沒配置,直接手動切換到server目錄下,node server.js啟動項目,這樣這個伺服器就抛出了可以localhost:3001/api/index這個接口了,這個接口傳回的結果就是我們所需的了。

現在改改src/index.js中componentDidMount中的代碼

componentDidMount(){

let data

//注意,這裡3001 就是node啟用的端口

axios.get('http://localhost:3001/api/index',{

params:{ info:'今天我最美',

userId:1234}

}).then(req=>{

{data} = req

})

this.setState({

content:data

})

}

這裡你就發現一個問題了,又一次出現了跨域,那現在這個跨域就很好解決了,配置下服務端代碼就可以了,我直接在server/server.js中用了koa-cros這個插件就可以啦,這裡注意,cors一定要放在路由的上面。

const Koa= require('koa')

const app = new Koa()

const routes = require('./routes.js');

const cors = require('koa2-cors');

//運作跨域

app.use(cors());

//路由

app.use(routes());

app.listen(3001,()=>{

console.log('port is running at 3001')

})

配置好了以後,又發現data取不到資料,這裡因為axios是異步的,資料還沒有擷取,頁面已經渲染完成了。因為axios傳回的是一個promise,是以這裡可以把componentDidMount改成異步等待的方法,取得data的值

async componentDidMount(){

//注意,這裡3001 就是node啟用的端口

const {data}= await axios.get('http://localhost:3001/api/index',{

params:{ info:'今天我最美',

userId:1234}

})

this.setState({

content:data

})

}

這樣資料就能顯示了

在調用過程中發現我對于post方式裡的Content-Type 的參數不是很清楚,下面我總結下Content-Type 幾種常用的參數的使用場景:(這裡為轉載)

application/x-www-form-urlencoded

這應該是最常見的 POST 送出資料的方式了。浏覽器的原生 form 表單,如果不設定 enctype 屬性,那麼最終就會以 application/x-www-form-urlencoded 方式送出資料。請求類似于下面這樣

POST http://www.example.com HTTP/1.1

Content-Type: application/x-www-form-urlencoded;charset=utf-8

title=test&sub%5B%5D=1&sub%5B%5D=2&sub%5B%5D=3

首先,Content-Type 被指定為 application/x-www-form-urlencoded;其次,送出的資料按照 key1=val1&key2=val2 的方式進行編碼,key 和 val 都進行了 URL 轉碼。大部分服務端語言都對這種方式有很好的支援。例如 PHP 中,

axios get怎麼還會顯示跨域_react+axios用node代了解決跨域

_POST[‘sub’] 可以得到 sub 數組。

很多時候,我們用 Ajax 送出資料時,也是使用這種方式。例如 JQuery 和 QWrap 的 Ajax,Content-Type 預設值都是「application/x-www-form-urlencoded;charset=utf-8」。

multipart/form-data

這又是一個常見的 POST 資料送出的方式。我們使用表單上傳檔案時,必須讓 form 的 enctyped 等于這個值。直接來看一個請求示例:

POST http://www.example.com HTTP/1.1

Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryrGKCBY7qhFd3TrwA

------WebKitFormBoundaryrGKCBY7qhFd3TrwA

Content-Disposition: form-data; name="text"

title

------WebKitFormBoundaryrGKCBY7qhFd3TrwA

Content-Disposition: form-data; name="file"; filename="chrome.png"

Content-Type: image/png

PNG ... content of chrome.png ...

------WebKitFormBoundaryrGKCBY7qhFd3TrwA--

這個例子稍微複雜點。首先生成了一個 boundary 用于分割不同的字段,為了避免與正文内容重複,boundary 很長很複雜。然後 Content-Type 裡指明了資料是以 mutipart/form-data 來編碼,本次請求的 boundary 是什麼内容。消息主體裡按照字段個數又分為多個結構類似的部分,每部分都是以 –boundary 開始,緊接着内容描述資訊,然後是回車,最後是字段具體内容(文本或二進制)。如果傳輸的是檔案,還要包含檔案名和檔案類型資訊。消息主體最後以 –boundary– 标示結束。關于 mutipart/form-data 的詳細定義,請前往 rfc1867 檢視。

這種方式一般用來上傳檔案,各大服務端語言對它也有着良好的支援。

上面提到的這兩種 POST 資料的方式,都是浏覽器原生支援的,而且現階段原生 form 表單也隻支援這兩種方式。但是随着越來越多的 Web 站點,尤其是 WebApp,全部使用 Ajax 進行資料互動之後,我們完全可以定義新的資料送出方式,給開發帶來更多便利。

application/json

application/json 這個 Content-Type 作為響應頭用來告訴服務端消息主體是序列化後的 JSON 字元串。由于 JSON 規範的流行,除了低版本 IE 之外的各大浏覽器都原生支援 JSON.stringify,服務端語言也都有處理 JSON 的函數,使用 JSON 不會遇上什麼麻煩。

JSON 格式支援比鍵值對複雜得多的結構化資料,這一點也很有用。

例如下面這段代碼:

var data = {'title':'test', 'sub' : [1,2,3]};

$http.post(url, data).success(function(result) {

...

});

最終發送的請求是:

POST http://www.example.com HTTP/1.1

Content-Type: application/json;charset=utf-8

{"title":"test","sub":[1,2,3]}

這種方案,可以友善的送出複雜的結構化資料,特别适合 RESTful 的接口。各大抓包工具如 Chrome 自帶的開發者工具、Firebug、Fiddler,都會以樹形結構展示 JSON 資料,非常友好。但也有些服務端語言還沒有支援這種方式,例如 php 就無法通過 $_POST 對象從上面的請求中獲得内容。這時候,需要自己動手處理下:在請求頭中 Content-Type 為 application/json 時,從 php://input 裡獲得原始輸入流,再 json_decode 成對象。

text/xml

它是一種使用 HTTP 作為傳輸協定,XML 作為編碼方式的遠端調用規範。XML-RPC 協定簡單、功能夠用,各種語言的實作都有。JavaScript 中,也有現成的庫支援以這種方式進行資料互動,能很好的支援已有的 XML-RPC 服務。