JSONP in HTML tags, some tags such as script, img, such as access to resources are not cross-domain restrictions, to take advantage of this, we can do:
Write a small interface on the back end
Const {successBody} = require('.. /utli') class CrossDomain {static async jsonp (CTX) {const query = ctx.request.query Ctx.cookie. set('tokenId', '1') // query.cb is the method name of the convention, which means that the back end returns a directly executed method to the front end. And put the data to be returned in the method parameters. ctx.body = `${query.cb}(${JSON.stringify(successBody({msg: query.msg}, 'success'))})` } } module.exports = CrossDomainCopy the code
The front-end code
<! DOCTYPE HTML > < HTML > <head> <meta charset=" utF-8 "> </head> <body> <script type='text/javascript'> This is equivalent to executing this method, and since the back end puts the returned data in the parameter of the method, it gets the RES here. window.jsonpCb = function (res) { console.log(res) } </script> <script src='http://localhost:9871/api/jsonp? msg=helloJsonp&cb=jsonpCb' type='text/javascript'></script> </body> </html>Copy the code
Front-end code simple encapsulation
/** * JSONP request tool * @param url request address * @param data request parameter * @returns {Promise<any>} */ const request = ({url, data}) => { return new Promise((resolve, Reject) => {const handleData = (data) => {const keys = object.keys (data) const keysLen = keys.length return keys.reduce((pre, cur, index) => { const value = data[cur] const flag = index ! == keysLen - 1 ? '&' : '' return `${pre}${cur}=${value}${flag}` }, } const script = document.createElement('script') // Get window.jsonpcb = (res) => { document.body.removeChild(script) delete window.jsonpCb resolve(res) } script.src = `${url}? ${the handleData (data)} & cb = jsonpCb ` document. The body. The appendChild (script)})} / / use the request ({url: 'http://localhost:9871/api/jsonp' data: {/ / preach and MSG: 'helloJsonp'}}). Then (res = > {the console. The log (res)})Copy the code
2. Empty iframe and add form
If you’re careful, you might notice that JSONP can only make GET requests, because essentially a script load resource is a GET, so what if you want to make POST requests?
The backend interface
Const {successBody} = require('.. /utli') class CrossDomain { static async iframePost (ctx) { let postData = ctx.request.body console.log(postData) ctx.body = successBody({postData: postData}, 'success') } } module.exports = CrossDomainCopy the code
The front end
const requestPost = ({url, Const iframe = document.createElement('iframe') iframe.name = 'iframePost' iframe.style.display = 'none' document.body.appendChild(iframe) const form = document.createElement('form') const node = Document.createelement ('input') // Register the load event handler for iframe if you need to do something when the response returns. Function () {console.log('post success')}) form.action = url // Execute form form.target = iframe.name in the specified iframe form.method = 'post' for (let name in data) { node.name = name node.value = data[name].toString() Form. The appendChild (node. The cloneNode ())} / / form elements need to be added to the main document. The form, style, display = 'none' document. The body. The appendChild (form) Form. Submit () / / after the form is submitted, you can delete the form, does not affect the next data. The document. The body. RemoveChild (form)} / / use requestPost ({url: 'http://localhost:9871/api/iframePost', data: { msg: 'helloIframePost' } })Copy the code
3.CORS
CORS is a W3C standard, full name is “cross-origin Resource Sharing” (CROSS-domain resource sharing) CORS details. As the name suggests, this is standard practice for dealing with cross-domain problems. CORS has two types of requests, simple and non-simple.
Here is a reference to the above link ruan Yifeng teacher’s article to explain the simple request and non-simple request. Browsers classify CORS requests into two categories: Simple request and not-so-simple Request.
As long as the following two conditions are met, it is a simple request. (1) Request method is one of the following three methods:
- HEAD
- GET
- POST
(2) HTTP headers do not exceed the following fields:
- Accept
- Accept-Language
- Content-Language
- Last-Event-ID
- Content-type: Application/X-www-form-urlencoded, multipart/form-data, text/plain
1. Simple requests
The back-end
Const {successBody} = require('.. /utli') class CrossDomain {static async cors (CTX) {const query = ctx.request.query // * When cookies are not carried in HTTP requests ctx.set('Access-Control-Allow-Origin', '*') ctx.cookies.set('tokenId', '2') ctx.body = successBody({msg: query.msg}, 'success') } } module.exports = CrossDomainCopy the code
The front end doesn’t have to do anything, just make normal requests, and if cookies are required, both the front and back ends need to be set, as you’ll see in the non-simple request example below.
fetch(`http://localhost:9871/api/cors? msg=helloCors`).then(res => { console.log(res) })Copy the code
2. Non-simple requests
A non-simple request will issue a precheck request with a return code of 204. The request will not actually be issued until the precheck passes, and 200 will be returned. A non-simple request is triggered by adding an extra HEADERS to the request.
The back-end
Const {successBody} = require('.. /utli') class CrossDomain {static async cors (CTX) {const query = ctx.request.query The credentials need to be set on both the front and back ends. Set (' access-Control-allow-origin ', 'http://localhost:9099') ctx.set(' access-Control-allow-credentials ', true) // For CORS requests that are not simple, an HTTP query is added before formal communication. Called a "preflight" request (preflight) // In this case, instead of setting origin, Set access-Control-request-method (' access-Control-request-method ') Headers ctx.set(' access-Control-request-method ') 'PUT,POST,GET,DELETE,OPTIONS') ctx.set('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, t') ctx.cookies.set('tokenId', '2') ctx.body = successBody({msg: query.msg}, 'success') } } module.exports = CrossDomainCopy the code
With so much code for one interface, what’s a more elegant way to treat all interfaces the same? See KOA2-CORS below.
const path = require('path') const Koa = require('koa') const koaStatic = require('koa-static') const bodyParser = require('koa-bodyparser') const router = require('./router') const cors = require('koa2-cors') const app = new Koa() App.use (koaStatic(path.resolve(__dirname, '.. Use (cors({origin: function (CTX) {return 'http://localhost:9099'}, credentials: true, allowMethods: ['GET', 'POST', 'DELETE'], allowHeaders: ['t', 'content-type ']}) // app.use(router.routes()).use(router.allowedmethods ()) // app.listen(9871) console.log(`[demo] start-quick is starting at port ${port}`)Copy the code
The front end
fetch(`http://localhost:9871/api/cors? MSG =helloCors ', {// The cookie credentials: 'include' is needed, // Add additional headers to trigger non-simple headers requests: {'t': 'extra headers' } }).then(res => { console.log(res) })Copy the code
4. The agent
Imagine if we still used a front-end domain name when requesting a domain name, and then had something to forward the request to a real back-end domain name for us. Wouldn’t that be cross-domain? This is where Nginx comes in. Nginx configuration
Server {# listen 9099; Localhost server_name localhost; Localhost :9099/ API: http://localhost:9871 location ^~ / API {proxy_pass http://localhost:9871; }}Copy the code
There’s nothing to do on the front end, nothing to do on the back end except write interfaces, right
Localhost :9099/ API: localhost:9099/ API: localhost:9099/ API: localhost:9099/ API Are forwarded to the real server address http://localhost:9871 the fetch (' http://localhost:9099/api/iframePost '{method: "POST", headers: {' Accept' : 'application/json', 'Content-Type': 'application/json' }, body: JSON.stringify({ msg: 'helloIframePost' }) })Copy the code
The way Nginx forwards seems convenient! If the back-end interface is a public API, such as some public service to get the weather, the front end of the call should not be used to configure Nginx, if compatibility is ok (IE 10 or above), CROS is more general practice.