Vue learning notes (III) concept and application of vue2's four slot slots | deconstruction and assignment of ES6 objects | GitHub case based on vue2 using Axios to send requests | browser cross domain problems and Solutions

You 2022-06-23 18:55:41 阅读数:812

vuelearningnotesiiiconcept

One 、 Reference material


Two 、 Running environment


  • Windows11
  • Visual Studio Code v2022
  • Node.js v16.5.01
  • Vue/cli v5.0.6
  • Bootstrap 5.1.3

3、 ... and 、Vue2 slot


Vue2 Implemented a set of content distribution API,, take <slot> Element as the exit to host the distribution .

effect : The parent component passes customized content to the child component by defining slots ( Data or function ).

3.1 Default slot

Next, an example is given to illustrate the role of slots .

For example App In the component :

<template>
<div>
<Header></Header>
</div>
</template>

I defined a template , There's a div,div It introduces a custom Vue Components Header

If I want to App Introduce Header Components , And add content to it , such as :

<Header>
<h1> Search engine </h1>
</Header>

By default ,<h1> It will not be rendered , Of course, other ordinary HTML Elements also do not render , You can use Vue Provided slot slot , We put a slot in this Header Inside the component , Like this :

( If you introduce Header When the component , There's nothing in it , Then there will be Header in <slot> Content of the label :“ Slot is empty ”

<template>
<div>
<slot> Slot is empty </slot>
</div>
</template>

This seems to be a reminder Vue:<slot> Here is a pit to be filled , Will be filled in by the parent component .

It is filled in by the parent component , therefore slot Slots can be used by parent components to pass data to child components .

Be careful , adopt slot Slot rendered elements , Its style can be set through the parent component .

3.2 A named slot

A named slot

According to the Vue Official documentation , The so-called named slot actually has name Slot for attribute value ,( from vue2.6.0 Start , Default slot name The value is default), For example, we can set multiple slots in the same component , In this way, the parent component of this component can insert elements into different slots .

The same to App Components and Header Component as an example .

Header Child components :

<template>
<div>
<slot name="a"> slot a It's empty </slot>
<slot name="c"> slot c It's empty </slot>
</div>
</template>

App Parent component :

<template>
<div>
<Header>
<h1 slot="a"> slot a</h1>
<h1 slot="c"> slot c Content 1</h1>
<h1 slot="c"> slot c Content 2</h1>
</Header>
</div>
</template>

Above App In the component h1 Tags can be other HTML label .

Specified here slot It can be reused , However, elements inserted into the same slot can be template The label refers to the slot of the stator assembly , Above App The abbreviated form of component code is as follows :

<template>
<div>
<Header>
<h1 slot="a"> slot a</h1>
<template slot="c">
<h1> slot c Content 1</h1>
<h1> slot c Content 2</h1>
</template>
</Header>
</div>
</template>

Be careful : At template Use it directly slot The writing of has been in Vue2.6.0 From being abandoned To view the document

Vue2.6.0 After version A named slot Usage is as follows To view the document

The way slots are declared remains the same ( But added default The default slot mechanism ):

<!-- The slot name is slot1 -->
<slot name="slot1"></slot>
<!-- The slot name defaults to default -->
<slot></slot>

When the parent component is introduced into the specified slot ,template Slots must be specified using v-slot , Be similar to v-on Of @ and v-bind Of :,v-slot Its short form is #, such as :

<template>
<div>
<Header>
<h1 slot="a"> slot a</h1>
<template #c>
<h1> slot c Content 1</h1>
<h1> slot c Content 2</h1>
</template>
</Header>
</div>
</template>

Be careful : v-slot Property only supported <template> label

meanwhile , Because the default name of the slot is "default ", So the parent component can specify the contents of the default slot :

<Header>
<template v-slot:default>
<h1> slot c Content 1</h1>
<h1> slot c Content 2</h1>
</template>
</Header>
<!-- The abbreviation is as follows -->
<Header>
<template #defualt>
<h1> slot c Content 1</h1>
<h1> slot c Content 2</h1>
</template>
</Header>

3.3 Scope slot

Use scenarios : The parent component will use the data of the child component when rendering elements , In this case, you can use the scope slot , Transfer the data in the child component that sets the slot to the parent component , It is convenient for the parent component to set elements in the child component .

stay Vue2 When introducing subcomponents in , The parent component can be :Key=Value To pass on value , For example App In the component :

<Header :name="uni"/>

Here we are introducing Header At the same time , Passed in a file named name, The value is "uni" The variable of .

And then in Header In the component, you can use { { name }} Get this value directly .

and <slot> Tags can also be passed in this way , For example Header Sub components :

<template>
<div>
<slot :name="uni"> slot a It's empty </slot>
</div>
</template>

This name Variables will be passed in to introduce this Header Parent component of component App, Then the parent component App Data can be obtained when writing slot elements :

<template>
<div>
<Header>
<template slot-scope="data">
<h1> {
{ data.name }}</h1>
</template>
</Header>
</div>
</template>

there slot-scope Declare the received prop The object will act as slotProps Variables exist in Scope . We can name things like JavaScript Name the function parameters at will data.

It may be more windy to say , The simple understanding is the scope slot , You can let child components pass data to parent components , However, the parent component can only get data inside the component tag .

Binding in <slot> Element attribute go by the name of slot prop.

About scope slots , An important official remark :

  • Everything in the parent template is compiled in the parent scope ;

  • Everything in the sub template is compiled in the sub scope .

Be careful : Passed above slot-scope To specify the scope of the method from Vue2.6.0 The beginning has been abandoned Official documents

Next is Vue2 The latest version of the scope slot usage Official documents

<template v-slot:default="data">
{
{ data.name }}
</template>
<!-- The abbreviation is as follows : -->
<template #default="data">
{
{ data.name }}
</template>

Actually, it's almost the same as before , The changes in the new version are template You have to use v-slot To specify the slot , Or specify the data introduced into the slot .

Same as the default slot , If no slot name is specified when importing data , Then the data will be obtained from the default slot

<template v-slot="data">
{
{ data.name }}
</template>

Here we need to pay attention to v-slot="data" and v-slot:default The difference between the two , The former obtains data from the default slot , Defined as data, The latter is designated as the default slot .

ES6 Deconstruction assignment concept & Deconstruction assignment of scope slot

ES6 The deconstruction assignment of

“ES6 It's a scripting language , From the name (ECMAScript6) We can see that , He is JS Component part , Straight white point , It defines how we write JS.”

ES6 Deconstruct assignment , It means that we are writing JavaScript Some special mechanisms that can be implemented in code .

In Deconstruction , There are two parts to participate in :

  • The source of deconstruction , Deconstruct the right part of the assignment expression .
  • The goal of deconstruction , Deconstruct the left part of the assignment expression .

stay Vue2 Deconstruction assignment in the scope slot , Is to convert the parameter value to Object object , So let's focus on ES6 Some mechanisms about the deconstruction and assignment of objects :
( Note here , The left side of the equation is equivalent to the subcomponent defining slot The parameter passed in when the tag , The right side of the equation is equivalent to the parent component inserting elements into the specified slot when , stay v-slot:xxx=“Object” Medium Object)

  • Basic deconstruction
let {
 foo, bar } = {
 foo: 'aaa', bar: 'bbb' };
// foo = 'aaa'
// bar = 'bbb'
let {
 baz : foo } = {
 baz : 'ddd' };
// foo = 'ddd' , It can be understood as replacing Key=baz Of Value
  • Can be nested and ignored
let obj = {
p: ['hello', {
y: 'world'}] };
let {
p: [x, {
 y }] } = obj;
// obj.x = 'hello'
// obj.y = 'world'
// PS: The previously used scope slots are similar to this kind of , The parent component only receives data assigned as obj , And then we passed obj To call the subcomponent in <slot> The attributes specified in 
let obj = {
p: ['hello', {
y: 'world'}] };
let {
p: [x, {
 }] } = obj;
// x = 'hello'
  • Incomplete deconstruction
let obj = {
p: [{
y: 'world'}] };
let {
p: [{
 y }, x ] } = obj;
// x = undefined
// y = 'world'
// Even though obj Inside p There is only one element in the object , But it can also be assigned to an object with two elements , The extra objects are undefined type 
  • Remainder operator
let {
a, b, ...rest} = {
a: 10, b: 20, c: 30, d: 40};
// a = 10
// b = 20
// rest = {c: 30, d: 40} The remaining elements will be assigned as objects to rest
  • Deconstruct default ( Only according to the corresponding Key Replace , Instead of replacing the whole Object object )
let {
a = 10, b = 5} = {
a: 3};
// a = 3; b = 5;
let {
a: aa = 10, b: bb = 5} = {
a: 3};
// aa = 3; bb = 5;

Array The deconstruction of the array model is similar to that of the object , But more about , stay Vue2 Object deconstruction is mainly used in Click to see

The internal working principle of a scoped slot is to wrap the contents of the slot in a function with a single parameter .

Deconstruct slot Prop , This is an extension of the official scope slot introduction , I think it's necessary Mark once , When using components in the future, you may need .

According to the official explanation , Let's take a practical example to understand this sentence :

  • Child components Header Component defines a slot
<template>
<div>
<h1> Head </h1>
<slot name="slot1" :username="username" :age="age"></slot>
</div>
</template>
<script> export default {
 name: 'Header', data(){
 return {
 username: 'uni', age: '22', } } } </script>
  • Parent component App Using slots (# yes v-slot Abbreviated form )
<template>
<div id="app">
<Header>
<!-- Fill the slot -->
<!-- <template #slot1="data"> <p> Output in different ways slot The data of : {
{data}}</p> <p> Get the properties of the object directly : {
{data.username}}</p> <p> Get the properties of the object directly : {
{data.age}}</p> </template> -->
<template #slot1="{username, age, abc}">
<p> Output in different ways slot The data of : {
{username}}, {
{age}}</p>
<p> When getting a parameter that does not exist :{
{typeof(abc)}}</p>
</template>
</Header>
</div>
</template>
<script> import Header from './components/Header.vue' export default {
 name: 'App', components: {
Header} } </script>

This is actually a parameter username and age Wrapped in a function , Similar to the following JS function :

function (data){

// The contents of the slot 
}
 This explanation v-slot Is actually anything that can be used as a parameter in a function definition JavaScript expression

Then in the sentence that the sub component declares the slot :

 <slot name="slot1" :username="username" :age="age"></slot>

Vue2 The work done at the bottom : From the present Vue In the component data Variable username and age, If data If there is no such thing as methods Search in , After finding the data , This data will be obtained when the parent component that fills the slot calls , For example, it should be :

{

username: 'uni',
age: '22',
}

This is a JS Medium Object object , And the inside value It is already a relatively simple string , In complex situations, it is possible to value
It will be a function , Or still an object , Layer upon layer .

Next, we will analyze in detail in the above cases , The deconstruction assignment occurs when the parent component fills the slot in two different cases :

Situation 1 : Specify as the entire object (slot If there are few parameters, you can use )

<template #slot1="data">
<p> Output in different ways slot The data of : {
{data}}</p>
<p> Get the properties of the object directly : {
{data.username}}</p>
<p> Get the properties of the object directly : {
{data.age}}</p>
</template>

Running effect :
 Insert picture description here

The deconstruction that happens here is : Basic deconstruction

// amount to 
let data = {

username: 'uni',
age: '22',
}

Situation two : Specify as object ( Recommended )

<template #slot1="{username, age, abc}">
<p> Output in different ways slot The data of : {
{username}}, {
{age}}</p>
<p> When getting a parameter that does not exist :{
{typeof(abc)}}</p>
</template>

Running effect :
 Insert picture description here
The deconstruction that happens here is : Basic deconstruction ( Same as before )

// amount to 
let {
username, age, abc} = {

username: 'uni',
age: '22',
}

From the above case, we can see , If { } The parameter values in the are in the slot Not specified in the tag , When the parent component calls, it defaults to undefined type .

We can solve this problem by deconstructing the following default values , Is to assign a default value when the data does not exist .

Advanced level of deconstruction : Default deconstruction

Suppose that the previous HTML Replace the code with the following :

<template #slot1="{username, age, abc='Vue666'}">
<p> Output in different ways slot The data of : {
{username}}, {
{age}}</p>
<p> When getting a parameter that does not exist , But when the default value is set :{
{abc}}</p>
</template>

Running effect :

 Insert picture description here
The deconstruction that happens here is : Default deconstruction

// amount to 
let {
username, age, abc='Vue666'} = {

username: 'uni',
age: '22',
}

Sum up ,Vue2 Scope slots support child components to pass parameters to parent components , Support at the same time ES6 The deconstruction assignment of .

3.4 Dynamic slot name

Dynamic slot name Refer to Dynamic instruction parameters It can also be used in v-slot On , To define a dynamic slot name :

Use the syntax :

<template v-slot:[dynamicSlotName]>
...
</template>

Case study :

  • Header Child components :
<template>
<div>
<h1> Head </h1>
<slot name="slot1" :title="' slot 1'"></slot>
<slot name="slot2" :title="' slot 2'"></slot>
</div>
</template>
<script> export default {
 name: 'Header', } </script>
  • App Parent component :
<template>
<div id="app">
<button @click="slotType = 'slot1'"> Select slot 1</button>
<button @click="slotType = 'slot2'"> Select slot 2</button>
<Header>
<template #[slotType]="title">
The currently selected slot is : {
{title}}
</template>
</Header>
</div>
</template>
<script> import Header from './components/Header.vue' export default {
 name: 'App', data(){
 return {
 slotType: 'slot1' } }, components: {
Header} } </script>

Realization effect :

 Insert picture description here
Pictured above , Dynamic slots support parent components to introduce slots of child components in different scenarios .

Four 、GitHub User search case


Make a simple search page , After the user enters the user name , send out GET Ask to GitHub Provided interface , Get the list information of the corresponding user name ( part ), The final list information will be displayed on the page .

The effect is as follows :

 Insert picture description here

4.1 Prepare static HTML file

index.html

<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<!-- introduce Bootstrap style -->
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript>
<strong> Browser does not support JavaScript. </strong>
</noscript>
<h1 class="text-center"> be based on Vue2 Of GitHub User search case </h1>
<!-- Container Begin-->
<div class="container shadow">
<!--Head Search bar Begin-->
<div class="mb-3 row">
<label for="input-search" class="col-sm-2 col-form-label text-end"> Search for GitHub user </label>
<div class="col-sm-8">
<input class="form-control" id="input-search">
</div>
<div class="col-sm-2">
<button class="btn btn-primary"> Search for </button>
</div>
</div>
<!--Head Search bar End -->
<!--Body GitHub User list Begin -->
<div class="container">
<ul class="list-unstyled row row-cols-md-4 ">
<li class="mb-5">
<div class="card text-center mx-auto" style="width: 120px;">
<div>
<img src="logo.png" class="card-img-top mx-auto shadow" style="width: 100px;height: 100px;border-radius: 50%;">
</div>
<div class="card-body">
<p class="card-text text-success"> user name </p>
</div>
</div>
</li>
<li class="mb-5">
<div class="card text-center mx-auto" style="width: 120px;">
<div>
<img src="logo.png" class="card-img-top mx-auto shadow" style="width: 100px;height: 100px;border-radius: 50%;">
</div>
<div class="card-body">
<p class="card-text text-success"> user name </p>
</div>
</div>
</li>
<li class="mb-5">
<div class="card text-center mx-auto" style="width: 120px;">
<div>
<img src="logo.png" class="card-img-top mx-auto shadow" style="width: 100px;height: 100px;border-radius: 50%;">
</div>
<div class="card-body">
<p class="card-text text-success"> user name </p>
</div>
</div>
</li>
<li class="mb-5">
<div class="card text-center mx-auto" style="width: 120px;">
<div>
<img src="logo.png" class="card-img-top mx-auto shadow" style="width: 100px;height: 100px;border-radius: 50%;">
</div>
<div class="card-body">
<p class="card-text text-success"> user name </p>
</div>
</div>
</li>
</ul>
</div>
<!--Body GitHub User list End-->
</div>
<!-- Container End -->
<!-- Vue2 App Component entrance -->
<div id="app"></div>
</body>
</html>

Running effect :

 Insert picture description here

4.2 Divide components according to static files

In addition to managing the main page App Beyond the components , The page is internally divided into Header Search and Body The user list displays
 Insert picture description here

4.3 Code implementation

index.html

<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<!-- introduce Bootstrap style -->
<!-- <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"> -->
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript>
<strong> Browser does not support JavaScript. </strong>
</noscript>
<h1 class="text-center"> be based on Vue2 Of GitHub User search case </h1>
<!-- Vue2 App Component entrance -->
<div id="app"></div>
</body>
</html>

Main.js

import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
import vueResource from 'vue-resource'
//npm i vue-resource
// The use of plug-in vue-resource send out GET request 
Vue.use(vueResource)
new Vue({

el: '#app',
render: h => h(App),
beforeCreate(){

Vue.prototype.$bus = this
}
})

App.vue

The component communication adopts the same global event bus as the last time :

Vue Learning notes ( Two ) be based on Vue2 Of TodoList To do cases | localStorage The local store | Vue2 Publish and subscribe to | Vue2 Supported animation classes |JavaScript Prototype object

Here are mainly customized Header And custom Body Data communication between two components ,Header Responsible for search GitHub User information for , Send out , and Body Is responsible for receiving ( subscribe ) List data for users .

<template>
<!-- Container Begin-->
<div class="container shadow">
<!--Head Search bar Begin-->
<Header></Header>
<!--Head Search bar End -->
<!--Body GitHub User list Begin -->
<Body></Body>
<!--Body GitHub User list End-->
</div>
<!-- Container End -->
</template>
<script> // npm i bootstrap import 'bootstrap/dist/js/bootstrap' import 'bootstrap/dist/css/bootstrap.min.css' import Header from './components/GitHubHeader.vue' import Body from './components/GitHubBody.vue' export default {
 name: 'App', components: {
Header, Body}, } </script>

GitHubHeader.vue be based on axios send out AJAX request

<template>
<div class="mb-3 row">
<label for="input-search" class="col-sm-2 col-form-label text-end"> Search for GitHub user </label>
<div class="col-sm-8">
<input class="form-control" id="input-search" v-model="searchName">
</div>
<div class="col-sm-2">
<button class="btn btn-primary" @click="search()"> Search for </button>
</div>
</div>
</template>
<script> import axios from 'axios' export default {
 name: 'Header', data(){
 return {
 searchName: '' } }, methods: {
 search(){
 // Prevent users from entering empty names  if(this.searchName === '') return this.$bus.$emit( 'selectUserByName', {
isFirst: false, errorMsg: ' Cannot query an empty name '} ) // Publish loaded messages  this.$bus.$emit('selectUserByName', {
errorMsg: '', isFirst: false, isLoading: true}) // Mode one : Use axios /* axios.get(`https://api.github.com/search/users?q=${this.searchName}`).then( response => { console.log(' The request is successful ') // Publish the message of successful request this.$bus.$emit('selectUserByName', { errorMsg: '', isLoading: false, userList: response.data.items, }) }, error => { console.log(' request was aborted ', error.message) // Publish the message that the request failed this.$bus.$emit('selectUserByName', { isLoading: false, errorMsg: ' Failed to get data ' }) } ) */ // Mode two : Use vue-resource this.$http.get(`https://api.github.com/search/users?q=${
this.searchName}`).then( response => {
 console.log(' The request is successful ') // Publish the message of successful request  this.$bus.$emit('selectUserByName', {
 errorMsg: '', isLoading: false, userList: response.data.items, }) }, error => {
 console.log(' request was aborted ', error.message) // Publish the message that the request failed  this.$bus.$emit('selectUserByName', {
 isLoading: false, errorMsg: ' Failed to get data ' }) } ) } }, } </script>

GitHubBody.vue

<template>
<div class="container">
<!-- Welcome tips -->
<h1 v-show="info.isFirst" class="text-center"> Welcome to visit </h1>
<!-- Error message -->
<h1 v-show="info.errorMsg" class="text-center text-danger"> error : {
{ info.errorMsg }}</h1>
<!-- Loading page -->
<div v-show="info.isLoading" class="d-flex justify-content-center">
<div v-show="info.isLoading" class="spinner-border text-info" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>
<!-- User list -->
<h5 v-show="info.userList.length" > common {
{info.userList.length}} Bar result </h5>
<ul v-show="info.userList.length" class="list-unstyled row row-cols-md-4 ">
<li class="mb-5" v-for="(user) in info.userList" :key="user.name">
<div class="card text-center mx-auto" style="width: 120px;">
<div>
<a :href="user.html_url" target="_blank">
<img :src="user.avatar_url" class="card-img-top mx-auto shadow" style="width: 100px;height: 100px;border-radius: 50%;">
</a>
</div>
<div class="card-body">
<p class="card-text text-success"> {
{ user.login }} </p>
</div>
</div>
</li>
</ul>
</div>
</template>
<script> export default {
 name: 'Body', data(){
 return {
 info:{
 isFirst: true, // On the first visit , The default is true isLoading: false, // Load tag  errorMsg: '', // error message  userList:[] // User data  } } }, methods: {
 }, mounted(){
 // subscribe ( Merging parameters ) this.$bus.$on('selectUserByName', (newInfo)=>{
 this.info = {
...this.info, ...newInfo} }) }, beforeDestroy(){
 this.$bus.$off('selectUserByName') } } </script>

5、 ... and 、 Browser cross domain

reference

[1] Zhouxiaoli .Ajax Cross domain access Web Services[J]. Computer programming skills and maintenance ,2014(08):93-96.DOI:10.16184/j.cnki.comprg.2014.08.058.
[2] Explain several methods of browser cross domain

5.1 What is browser cross domain

stay WEB In front end development , The most common cross domain problem is that the browser is A Domain name page sent B Domain name requests will be restricted .

This kind of cross domain often comes from URL Of GET Request or JavaScript adopt AJAX Sent GET、POST Equal request .

AJAX yes Asynchronus JavaScript and XML( asynchronous JavaScript and XML) Abbreviation ,AJAX Mainly used XMLHttpRequest, Asynchronous data reading technology , So that we can initiate Web request , Data interaction with remote server .[1]

stay Vue in , Usually use axios Send asynchronous request , instead of AJAX.

axios Technology is based on JS Of Promise Realized ,Promise It's a ECMAScript 6 Class provided , The goal is to write complex asynchronous tasks more gracefully , therefore axios And ajax The biggest difference is ,axios Support Promise Medium API, So in Vue In technology ,axios Is the mainstream technology for sending requests .

and axios and ajax In essence, it is to a certain URL Send a request , Next, we will use AJAX To describe cross domain problems .

Tradition Web Applications and Ajax The way of Web The comparison of application interaction modes is shown in the following figure :
 Insert picture description here

As you can see from the diagram , Use AJAX Technology can reduce the time users spend waiting on front-end pages , Enhance the user experience .
Use AJAX technology-built Web page , Reload and dynamically update without terminal interaction process .[1]

When using AJAX When requesting resources from the server , At this point, security issues will be involved , In common JavaWeb In development , Usually by Tomcat Deploy Web project , If it is deployed locally , That's not going to happen :

For example login.html Login page , After clicking login, you need to send a login request to the server , For example, to /user/login Send a request , Why can we access the server directly at this time ? It's not hard to understand , After all, it is on the same machine , Then there will certainly be no permission problem .

Actually in Web Browser , There is a rule that limits JavaScript Access to script code , It doesn't mean which server you want to send the request to , The server will accept , Usually JS There are two kinds of restrictions . The first is to restrict the operation permission of the client , The second is to restrict remote operations .

JS Restrictions on operating clients

1) Local files and directories are not allowed to be written
2) Deleting local files and directories... Is not allowed

To put it bluntly, local files and directories can only be read , The most common is to set the avatar , For example, we can be in CSDN Modify your avatar in the personal center of the website , The operation of modifying the avatar is essentially through JavaScript Code to read the local files of our computer , But we can't modify the files on our computer in the website , This is not allowed , Otherwise, when we enter a maliciously tampered website , In case of permission , Your computer files will be modified or deleted , Then there will be serious problems .

JS Limitation of remote operation

JavaScript The restrictions that script code places on remote servers are called The same-origin policy (Same-Origin Policy), namely JS A script can only access the same domain as the document containing it (domain) Documents under .

What is a domain ?

First, a remote web page URL It consists of four parts : agreement :// host : Port number / route , such as :http://localhost:8080( Now the path is /

The same domain means two URL Of agreement :// host : port this 3 The two parts are the same .

HTTP The default port number for the protocol is 80,HTTPS The default port number for the protocol is 443, Because it is an international standard , When we visit a web page , These two port numbers are not displayed , And we are deploying ourselves Web Project time , You can specify other port numbers , such as 8080、8081、80 etc. , The most common http://localhsot:8080 This URL For example , The same origin or cross domain URL The style is as follows ( The default local host name is DNS The host name of the domain name configuration is the same as IP Different ):

JS Access to the URL access reason
http://localhost:8080/user/login Homology
http://localhost:8080/index Homology
http://uni:8080 Cross domain The mainframe is different
http://www.localhost:8080 Cross domain The mainframe is different
http://localhost:80 Cross domain Different ports
https://localhost:8080 Cross domain Different agreements

according to [2] Examples presented in :

A The website is a bank website ,A The website sets up a Cookie, Contains some privacy information ( For example, the total amount of deposits ), When the user leaves A After website , To visit again B Website , If there is no homology restriction , that B The website can read A Website Cookie, Then private information will be leaked . It's even scarier , Some websites use Cookie To save the user's login status , If the user does not log out , Other websites can impersonate users , Do as one pleases .

stay Web When the front end is not the same source , There are three behaviors that are restricted :

  • Cookie、LocalStorage and IndexDB Can't read
  • DOM Can't get
  • AJAX Request cannot be sent

Because of this limitation , When we visit different websites , Use the browser debugging tool to view Cookie、localStorage、IndexDB This information , The results are different , Although they are all stored on our local machine , But different websites can only read their own information from our machines , We can't read the information saved on our machine by other websites .

Use a case to view cross domain issues :

Back end SpringBoot Provide an interface ,/hello, This interface returns a simple JSON data , The format is as follows :

{

code: '200',
msg: ' How are you? !'
}

Controller Layer code :

package com.uni.crossdomain.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
public class UserController {

@GetMapping("/hello")
public Map<String, Object> hello(){

return new HashMap<String, Object>(){
{

put("code", 200);
put("msg", " How are you? !");
}};
}
}

Running effect :

 Insert picture description here
Next , Use vscode edit HTML page , Use Live Server The plug-in deploys a port with the number 5000 Front end projects

HTML The code is as follows ( Use JQuery Realization AJAX request ):

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<html>
<title> Cross domain testing </title>
</head>
<body>
<h1> Request to be sent </h1>
<button onclick="get(this)"> Click to http://localhost:8080/hello send out AJAX request </button>
<script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<script type="text/javascript"> function get(btn){
 $.ajax({
 url: 'http://localhost:8080/hello', type: 'GET', error: (errMsg) =>{
 alert(' request was aborted ') $(btn).prev().text(JSON.stringify(errMsg)) }, success: (data) =>{
 alert(' The request is successful ') $(btn).prev().text(JSON.stringify(data)) } }) } </script>
</body>
</html>

 Insert picture description here
At this time, the backend does not receive any information ,AJAX The error message returned is :

{

"readyState":0
"status":0,
"statusText":"error"
}

The browser error message is :

Access to XMLHttpRequest at ‘http://localhost:8080/hello’ from origin ‘http://127.0.0.1:5500’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.

After translation :

Access at ’http://localhost:8080/hello’ From the origin ’http://127.0.0.1:5500“” Has been CORS Policy prevents : The requested resource does not exist “Access Control Allow Origin” header .

You can see , Because I use 5500 Port number to request 8080 The port number of the resource , Here is CORS Policy intercepted , But the localhost and 127.0.0.1, That is, the requested host is the same , Because on this computer DNS Domain name profile ( Default in C:\Windows\System32\drivers\etc\hosts) There is a comment in , namely localhost It's essentially 127.0.0.1 The address of .

# localhost name resolution is handled within DNS itself.
# 127.0.0.1 localhost
# ::1 localhost

5.2 Browser cross domain solution

CORS standard

CORS It's a W3C standard , The full name is cross domain resource sharing (CORSs-origin resource sharing), It allows the browser to cross to the source server , issue XMLHttpRequest request .
Actually , To be exact , Cross domain mechanism is to prevent cross domain data acquisition , It's not preventing requests from being sent .
CORS Requires both browser and server support . at present , All browsers support this feature ,IE The browser cannot be lower than IE10.[2]

Whole CORS Communication process , It's all done automatically by the browser , No user involvement is required . For developers ,CORS Correspondence and homology AJAX There is no difference in communication , The code is exactly the same . Once the browser finds AJAX Request cross source , Will automatically add some additional header information , Sometimes there is an additional request , But users don't feel .[2]

therefore , Realization CORS The key to communication is the server . As long as the server implements it CORS Interface , You can communicate across domains . For more information, please refer to the article Click to see , Here is mainly to understand .

JSONP Cross domain

stay HTML In the document , Usually introduced JS For example :

 <script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<script type="text/javascript"> ... Customize JS Script </script>

Browser loading HTML When the document , Will load in sequence script In the label src The address of , This kind of loading can be cross domain , Browsers don't block cross domain js load .

For example, in the last case

From local http://127.0.0.1:5000 towards https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js Request got JS The script resource , thus , Self defined JS In the script, you can use JQuery Function of , This is a real case of cross domain access to resources .

Besides , also img Such as tag , It can be loaded across domains , For example, we can introduce pictures on the Internet into our website .

and JSONP It is the use of script/img Tags can be loaded across domains , To realize the function of cross domain request , for example :

function showData(data){

console.log(data);
}
$('body').append(`<script src='http://localhost:8080/hello?callback=showData'><\/script>`);

test result :

Cross source read blocking (CORB) Function prevents MIME The type is application/json Cross source response of http://localhost:8080/hello?callback=showData&_=1655954732590. For more information , see also https://www.chromestatus.com/feature/5629709824032768.

Still failed , This is because the server does not support CORB Cross domain , This BUG Will be used below Vue2 Supported proxy server solutions .

Proxy server cross domain 【Vue The strategy adopted 】

Reference article : Easy to understand Nginx working principle

mention proxy Reverse proxy has to say Nginx This is a very popular framework .

Nginx (engine x) Is a high-performance HTTP And reverse proxy web The server , It also provides IMAP/POP3/SMTP service .

Ngnix There are many advantages : modularization 、 asynchronous 、 Multi process single thread, etc , besides , It solves Ajax Cross domain issues .

 Insert picture description here

After learning about such a cross domain solution , Let's get familiar with Vue2 Cross domain processes are configured in .

Core configuration :devServer.proxy

Type: string | Object

If your front-end application and back-end API The server is not running on the same host , You need to put... In a development environment API Ask the agent to API The server . This problem can be solved by vue.config.js Medium devServer.proxy Options to configure .

Case study : It's the same as before 5.1 Cross domain cases mentioned in section .

SpringBoot Back end , The port number is 8080,Controller Layer for :

package com.uni.crossdomain.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
public class UserController {

@GetMapping("/hello")
public Map<String, Object> hello(){

return new HashMap<String, Object>(){
{

put("code", 200);
put("msg", " How are you? !");
}};
}
}

front end Vue2 The scaffold :
vue.config.js

const {
 defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({

// close eslint Syntax check 
lintOnSave: false,
devServer: {

// Configure the port number of the local server 
port: 5000,
// Turn on the proxy server 
/* Mode one : No prefix , When initiating local 5000 Port request , If the resource is not found locally , Just ask to 8080 port shortcoming : 1) Only single request forwarding can be configured 2) Duplicate paths and static resources are not supported , As requested http://localhost:5000/hello when , You will first search locally hello The static resource file of , If not, it will be forwarded to http://localhost:8080/hello */
// proxy: 'http://localhost:8080'
/* Mode two : Prefixed configuration ( Multiple agents can be set ) */
proxy: {

'/springboot': {

target: 'http://localhost:8080',
ws: true, // Used to support websocket
pathRewrite: {
'^/springboot':''},
changeOrigin: false // Set whether the proxy server sends real local messages URL
}
}
}
})

App.vue

<template>
<div>
<h1> {
{info}} </h1>
<button @click="get()"> towards {
{reqUrl}} Send a request </button>
</div>
</template>
<script> import axios from 'axios' export default {
 name: 'App', data(){
 return {
 reqUrl: 'http://localhost:5000/springboot/hello', info: ' Request content ' } }, methods: {
 get(){
 axios.get(this.reqUrl).then( response => {
 alert(' The request is successful !') this.info = response.data }, error => {
 alert(' request was aborted .') this.info = error.message } ) } } } </script>

Running results :

 Insert picture description here
notes : Back end here SpringBoot There is no cross domain configuration , This is by Vue2 The internally provided proxy server implements cross domain .

5.3 Vue2 Scaffolding to achieve cross domain summary

Mode one : stay vue.config.js Add configuration in

devServer: {

proxy: "http://localhost:5000"
}
  • advantage : Simple configuration , When requesting resources, it is sent directly to the front end 8080, It will forward it to 5000

  • shortcoming : Cannot configure multiple agents , Unable to flexibly control whether the request should be proxied

  • Operating mechanism : Follow the above configuration , When a resource that does not exist in the front end is requested , Then the request will be forwarded to the configured server ( That is, the local front-end resources should be matched first )

Mode two : stay vue.config.js Add specific proxy rules to

module.exports = defineConfig({

// close eslint Syntax check 
lintOnSave: false,
devServer: {

// Configure the port number of the local server 
port: 5000,
proxy: {

'/springboot': {
 // Match all to '/springboot' The request path at the beginning 
target: 'http://localhost:8080', // The base path of the proxy target 
ws: true, // Used to support websocket
pathRewrite: {
'^/springboot':''}, // Regular replacement path when sending request 
changeOrigin: true // Set whether the proxy server sends real local messages URL( Recommended as true)
},
'/uni': {
 // Match all to /uni The request path at the beginning 
target: 'http://localhost:8081', // The base path of the proxy target 
pathRewrite: {
'^/uni':''} // Regular replacement path when sending request 
changeOrigin: true
}
}
})
版权声明:本文为[You]所创,转载请带上原文链接,感谢。 https://qdmana.com/2022/174/202206231738391625.html