简体   繁体   English

错误:找不到'[object Object]'的NgModule元数据

[英]Error: No NgModule metadata found for '[object Object]'

I am attempting to convert my angular 6 application to server side rendering (for SEO purposes), and everything seems to compile without error. 我试图将我的角度6应用程序转换为服务器端渲染(用于搜索引擎优化目的),一切似乎编译没有错误。 Except when I actually navigate to the to localhost, I and getting the full error of 除非我实际导航到localhost,否则我将获得完整的错误

Error: No NgModule metadata found for '[object Object]'.
at NgModuleResolver.resolve (/execroot/angular/packages/compiler/src/ng_module_resolver.ts:31:15)
at CompileMetadataResolver.getNgModuleMetadata (/execroot/angular/packages/compiler/src/metadata_resolver.ts:509:41)
at JitCompiler._loadModules (/execroot/angular/packages/compiler/src/jit/compiler.ts:127:49)
at JitCompiler._compileModuleAndComponents (/execroot/angular/packages/compiler/src/jit/compiler.ts:107:32)
at JitCompiler.compileModuleAsync (/execroot/angular/packages/compiler/src/jit/compiler.ts:61:33)
at CompilerImpl.compileModuleAsync (/execroot/angular/packages/platform-browser-dynamic/src/compiler_factory.ts:57:27)
at /execroot/nguniversal/modules/express-engine/src/main.ts:130:16
at new ZoneAwarePromise (/Users/melliotfrost/projects/myapp/node_modules/zone.js/dist/zone-node.js:891:29)
at getFactory (/execroot/nguniversal/modules/express-engine/src/main.ts:115:10)
at View.engine (/execroot/nguniversal/modules/express-engine/src/main.ts:92:7)

I am running the commands npm run build:ssr && npm run serve:ssr 我正在运行命令npm run build:ssr && npm run serve:ssr

app.module.ts (Main module) app.module.ts(主要模块)

 //import modules import { BrowserModule } from '@angular/platform-browser'; import { NgModule, APP_INITIALIZER, PLATFORM_ID, APP_ID, Inject } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; import { ColorPickerModule } from 'ngx-color-picker'; import { SortablejsModule } from 'angular-sortablejs'; import { FroalaEditorModule, FroalaViewModule } from 'angular-froala-wysiwyg'; import { Ng2SearchPipeModule } from 'ng2-search-filter'; import { MomentModule } from 'angular2-moment'; import { UIView } from '@uirouter/angular' import { FileUploadModule } from 'ng2-file-upload'; import { CustomFormsModule } from 'ng4-validators'; import { NgSelectModule } from '@ng-select/ng-select'; import { NgPipesModule } from 'angular-pipes'; import { NgxPaginationModule } from 'ngx-pagination'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { BusyModule } from 'angular2-busy'; import { CookieModule } from 'ngx-cookie'; //TODO will be fixed shortly //import { TextareaAutosizeModule } from 'ngx-textarea-autosize'; import { Location, LocationStrategy, HashLocationStrategy, isPlatformBrowser } from '@angular/common'; import * as _ from 'lodash'; //pipes import { AppPipes } from './pipes/pipes'; //Directives import { AppDirectives } from './directives/directives'; //Components import { AppComponents, ModalComponents } from './components/components'; import { AppComponent } from'./app.component'; //Services import { AppResources } from './components/resources'; import { AppServices } from './services/services'; import { AppLoadService } from '../config/app.load.service'; //HTTP Interceptors import { APIInterceptor } from './services/api.interceptor'; const interceptors = [ { provide: HTTP_INTERCEPTORS, useClass: APIInterceptor, multi: true } ]; //States import { AppRoutingModule } from './app-routing.module'; export function init_app(appLoadService: AppLoadService) { return () => appLoadService.load(); } //Platform Info const IMPORTS = [ BrowserModule.withServerTransition({ appId: 'myapp' }), FormsModule, BrowserAnimationsModule, HttpClientModule, NgbModule.forRoot(), ColorPickerModule, SortablejsModule.forRoot({ animation: 150 }), FroalaEditorModule.forRoot(), FroalaViewModule.forRoot(), Ng2SearchPipeModule, MomentModule, FileUploadModule, AppRoutingModule, CustomFormsModule, NgSelectModule, NgPipesModule, NgxPaginationModule, BusyModule, CookieModule.forRoot() //TextareaAutosizeModule ]; const DECLARATIONS = [ AppPipes, AppDirectives, AppComponents ]; const PROVIDERS = [ AppResources, AppServices, interceptors, Location, AppLoadService, { provide: APP_INITIALIZER, useFactory: init_app, deps: [AppLoadService], multi: true }, ]; @NgModule({ declarations: DECLARATIONS, imports: IMPORTS, providers: PROVIDERS, entryComponents: ModalComponents, bootstrap: [ AppComponent ], }) export class AppModule { constructor( @Inject(PLATFORM_ID) private platformId: Object, @Inject(APP_ID) private appId: string) { const platform = isPlatformBrowser(platformId) ? 'in the browser' : 'on the server'; console.log(`Running ${platform} with appId=${appId}`); } } 

main.ts main.ts

 import { enableProdMode } from '@angular/core'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { AppModule } from './app/app.module'; import { environment } from './environments/environment'; if (environment.production) { enableProdMode(); } platformBrowserDynamic().bootstrapModule(AppModule).catch(err => console.log(err)); 

tsconfig.app.json tsconfig.app.json

 { "extends": "../tsconfig.json", "compilerOptions": { "outDir": "../out-tsc/app", "baseUrl": "./", "module": "es2015", "types": [] }, "exclude": [ "test.ts", "**/*.spec.ts" ] } 

app.server.module.ts (Server module) app.server.module.ts(服务器模块)

 import { enableProdMode } from '@angular/core'; export { AppServerModule } from './app/app.server.module'; enableProdMode(); 

server.main.ts server.main.ts

tsconfig.server.json tsconfig.server.json

 { "extends": "../tsconfig.json", "compilerOptions": { "outDir": "../out-tsc/server", "baseUrl": "./", "module": "commonjs", "types": [] }, "exclude": [ "test.ts", "**/*.spec.ts" ], "angularCompilerOptions": { "entryModule": "app/app.server.module#AppServerModule" } } 

server.ts (server) server.ts(服务器)

webpackage.server.config.js (webpack configuration for generate server.js) webpackage.server.config.js(生成server.js的webpack配置)

 //******************** BEGING deps *******************// import 'zone.js/dist/zone-node'; import 'reflect-metadata'; import express = require('express'); import path = require('path'); import compression = require('compression'); import fs = require('fs'); import http = require('http'); import https = require('https'); import git = require('git-rev'); import request = require('request'); import fallback = require('express-history-api-fallback'); import bodyParser = require('body-parser'); import sslRedirect = require('heroku-ssl-redirect'); import { join } from 'path'; const ejs = require('ejs'); //******************** END deps *******************// // //******************** BEGING angular deps *******************// import { enableProdMode } from '@angular/core'; import { ngExpressEngine } from '@nguniversal/express-engine'; import { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader'; // //******************** END angular deps *******************// //******************** BEGING constants *******************// // require('dotenv').config(); enableProdMode(); const app = express(); const API_URL = { dev: 'https://dev-api.myapp.com', feature: 'https://localhost:1337', stage: 'https://test-api.myapp.com', demo: 'https://demo-api.myapp.com', prod: 'https://api.myapp.com' }; const root = 'dist'; const DIST_FOLDER = join(process.cwd(), 'dist'); //******************** END constants *******************// // //****************** BEGIN ANGULAR UNIVERSAL CONFIG *****************// const domino = require('domino'); const template = fs.readFileSync(path.join(root + '/browser', 'index.html')).toString(); const win = domino.createWindow(template); global['window'] = win; global['document'] = win.document; global['DOMTokenList'] = win.DOMTokenList; global['Node'] = win.Node; global['Text'] = win.Text; global['HTMLElement'] = win.HTMLElement; global['navigator'] = win.navigator; global['MutationObserver'] = getMockMutationObserver(); function getMockMutationObserver() { return class { observe(node, options) { } disconnect() { } takeRecords() { return []; } }; } var { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('./dist/server/main'); console.log(LAZY_MODULE_MAP); console.log(AppServerModuleNgFactory); //****************** END ANGULAR UNIVERSAL CONFIG *****************// //******************** BEGING server configs *******************// app.use(sslRedirect()); app.use(bodyParser.json()) //view enginer app.engine('html', ngExpressEngine({ bootstrap: AppServerModuleNgFactory, providers: [ provideModuleMap(LAZY_MODULE_MAP) ] })); app.set('view engine', 'html'); app.set('views', join(DIST_FOLDER, 'browser')); //******************** END server configs *******************// //************* BEGIN ROUTES *****************/ //server initial page //app.get('/', function(req, res){ //res.sendFile(path.join(__dirname + '/dist/index.html')); //}); app.get('/polyfills.bundle.js', (req, res) => { res.sendFile(path.join(__dirname + '/dist/polyfills.bundle.js')); }); app.get('/styles.bundle.js', (req, res) => { res.sendFile(path.join(__dirname + '/dist/styles.bundle.js')); }); app.get('/scripts.bundle.js', (req, res) => { res.sendFile(path.join(__dirname + '/dist/scripts.bundle.js')); }); app.get('/vendor.bundle.js', (req, res) => { res.sendFile(path.join(__dirname + '/dist/vendor.bundle.js')); }); app.get('/main.bundle.js', (req, res) => { res.sendFile(path.join(__dirname + '/dist/main.bundle.js')); }); app.get('/inline.bundle.js', (req, res) => { res.sendFile(path.join(__dirname + '/dist/inline.bundle.js')); }); //API routes app.get('/api/envInfo', function(req, res){ git.branch(function(branch){ git.short(function(hash){ res.json({ env: process.env.APP_ENV || 'dev', hash: hash, branch: branch }); }); }); }); app.get('/api/badge/:id', function(req, res){ var badgeUrl = API_URL[process.env.APP_ENV || 'dev'] + '/badge/' + req.params.id + '?withuser=true'; request.get(badgeUrl, (err, response, body) => { ejs.renderFile('./views/badge.ejs', { cert: JSON.parse(body) }, (err, html) => { res.send(html); }); }); }); app.get('/api/microcourse/:id', function(req, res){ var microcourseUrl = API_URL[process.env.APP_ENV || 'dev'] + '/earnedMicrocourse/' + req.params.id; request.get(microcourseUrl, (err, response, body) => { ejs.renderFile('./views/badge.ejs', { cert: JSON.parse(body) }, (err, html) => { res.send(html); }); }); }); app.get('/api/user/:id', function(req, res){ var userUrl = API_URL[process.env.APP_ENV || 'dev'] + '/user/' + req.params.id; request.get(userUrl, (err, response, body) => { var user = JSON.parse(body); if(user.profileVisible){ ejs.renderFile('./views/user.ejs', { user: JSON.parse(body) }, (err, html) => { res.send(html); }); } else { res.redirect('/#/'); } }); }); app.get('/api/badge/:id/share', function(req, res){ var badgeUrl = API_URL[process.env.APP_ENV || 'dev'] + '/badge/' + req.params.id + '?withuser=true&hide=true'; request.get(badgeUrl, (err, response, body) => { ejs.renderFile('./views/badge.ejs', { badge: JSON.parse(body) }, (err, html) => { res.send(html); }); }); }); app.post('/api/theme', require('./routes/generateTheme')); //Angular Routes // app.get('*.*', express.static(join(DIST_FOLDER, 'browser'))); app.get('*', (req, res) => { res.render('index', { req: req, res: res, providers: [ { provide: 'REQUEST', useValue: (req) }, { provide: 'RESPONSE', useValue: (res) } ] }); }); //***************** END Routes *****************// // //***************BEGIN app configurations *******************// //server gzipped content app.use(compression()); app.use('/images', express.static('images')); app.use('/assets', express.static('assets')); app.use('/dist', express.static('dist')); app.use('/node_modules', express.static('node_modules')); app.use('/app', express.static('app')); app.use('/public', express.static('public')); app.use(fallback('index.htm', { root: root })); //*************** END app configurations *******************// //*************** BEGIN server instantiation *******************// //SSL termination for heroku is handled by the load balancer //but locally is handled by node if(!process.env.APP_ENV || (process.env.APP_ENV === 'feature')){ var credentials = { key: fs.readFileSync(path.join('ssl', 'certs', 'server', 'privkey.pem')), cert: fs.readFileSync(path.join('ssl', 'certs', 'server', 'fullchain.pem')), ca: fs.readFileSync(path.join('ssl', 'certs', 'ca', 'my-root-ca.crt.pem')) }; var httpsServer = https.createServer(credentials, app); httpsServer.listen(process.env.PORT || 8080); } else { var httpServer = http.createServer(app); httpServer.listen(process.env.PORT || 8080); } //*************** END server instantiation *******************// 

 const path = require('path'); const webpack = require('webpack'); module.exports = { entry: { server: './server.ts' }, resolve: { extensions: ['.js', '.ts'] }, target: 'node', mode: 'none', // this makes sure we include node_modules and other 3rd party libraries externals: [/node_modules/], output: { path: __dirname, filename: '[name].js' }, module: { rules: [{ test: /\\.ts$/, loader: 'ts-loader' }] }, plugins: [ // Temporary Fix for issue: https://github.com/angular/angular/issues/11580 // for 'WARNING Critical dependency: the request of a dependency is an expression' new webpack.ContextReplacementPlugin( /(.+)?angular(\\\\|\\/)core(.+)?/, path.join(__dirname, 'src'), // location of your src {} // a map of your routes ), new webpack.ContextReplacementPlugin( /(.+)?express(\\\\|\\/)(.+)?/, path.join(__dirname, 'src'), {} ), ] }; 

angular.json (cli configuration) angular.json(cli配置)

 { "$schema": "./node_modules/@angular/cli/lib/config/schema.json", "version": 1, "newProjectRoot": "projects", "projects": { "browser": { "root": "", "sourceRoot": "src", "projectType": "application", "architect": { "build": { "builder": "@angular-devkit/build-angular:browser", "options": { "outputPath": "dist/browser", "index": "src/index.html", "main": "src/main.ts", "tsConfig": "src/tsconfig.app.json", "polyfills": "src/polyfills.ts", "assets": [ "src/assets" ], "styles": [ "src/styles.scss", "node_modules/froala-editor/css/froala_editor.pkgd.min.css", "node_modules/froala-editor/css/froala_style.min.css", "node_modules/sweetalert2/dist/sweetalert2.min.css", "node_modules/pnotify/dist/pnotify.css", "node_modules/@ng-select/ng-select/themes/default.theme.css", "node_modules/angular2-busy/build/style/busy.css" ], "scripts": [ "node_modules/sweetalert2/dist/sweetalert2.min.js", "node_modules/lodash/lodash.min.js", "node_modules/jquery-watch/jquery-watch.min.js", "node_modules/bootstrap/dist/js/bootstrap.min.js", "node_modules/socket.io-client/dist/socket.io.js" ] }, "configurations": { "production": { "optimization": true, "outputHashing": "all", "sourceMap": false, "extractCss": true, "namedChunks": false, "aot": true, "extractLicenses": true, "vendorChunk": false, "buildOptimizer": true, "fileReplacements": [ { "replace": "src/environments/environment.ts", "with": "src/environments/environment.prod.ts" } ] }, "demo": { "optimization": true, "outputHashing": "all", "sourceMap": false, "extractCss": true, "namedChunks": false, "aot": true, "extractLicenses": true, "vendorChunk": false, "buildOptimizer": true, "fileReplacements": [ { "replace": "src/environments/environment.ts", "with": "src/environments/environment.demo.ts" } ] }, "feature": { "fileReplacements": [ { "replace": "src/environments/environment.ts", "with": "src/environments/environment.feature.ts" } ] }, "stage": { "optimization": true, "outputHashing": "all", "sourceMap": false, "extractCss": true, "namedChunks": false, "aot": true, "extractLicenses": true, "vendorChunk": false, "buildOptimizer": true, "fileReplacements": [ { "replace": "src/environments/environment.ts", "with": "src/environments/environment.staging.ts" } ] } } }, "server": { "builder": "@angular-devkit/build-angular:server", "options": { "outputPath": "dist/server", "main": "src/server.main.ts", "tsConfig": "src/tsconfig.server.json", "bundleDependencies": "all" }, "configurations": { "production": { "browserTarget": "browser:build:production" }, "demo": { "browserTarget": "browser:build:demo" }, "feature": { "browserTarget": "browser:build:feature" }, "stage": { "browserTarget": "browser:build:stage" } } }, "extract-i18n": { "builder": "@angular-devkit/build-angular:extract-i18n", "options": { "browserTarget": "browser:build" } }, "test": { "builder": "@angular-devkit/build-angular:karma", "options": { "main": "src/test.ts", "karmaConfig": "./karma.conf.js", "polyfills": "src/polyfills.ts", "tsConfig": "src/tsconfig.spec.json", "scripts": [ "node_modules/sweetalert2/dist/sweetalert2.min.js", "node_modules/lodash/lodash.min.js", "node_modules/jquery-watch/jquery-watch.min.js", "node_modules/bootstrap/dist/js/bootstrap.min.js", "node_modules/socket.io-client/dist/socket.io.js" ], "styles": [ "src/styles.scss", "node_modules/froala-editor/css/froala_editor.pkgd.min.css", "node_modules/froala-editor/css/froala_style.min.css", "node_modules/sweetalert2/dist/sweetalert2.min.css", "node_modules/pnotify/dist/pnotify.css", "node_modules/@ng-select/ng-select/themes/default.theme.css", "node_modules/angular2-busy/build/style/busy.css" ], "assets": [ "src/assets" ] } }, "lint": { "builder": "@angular-devkit/build-angular:tslint", "options": { "tsConfig": [ "src/tsconfig.app.json", "src/tsconfig.spec.json" ], "exclude": [ "**/node_modules/**" ] } } } }, "browser-e2e": { "root": "", "sourceRoot": "", "projectType": "application", "architect": { "server": { "builder": "@angular-devkit/build-angular:server", "options": { "outputPath": "dist/server", "main": "src/main.server.ts", "tsConfig": "src/tsconfig.server.json" } }, "e2e": { "builder": "@angular-devkit/build-angular:protractor", "options": { "protractorConfig": "./protractor.conf.js", "devServerTarget": "browser:serve" } }, "lint": { "builder": "@angular-devkit/build-angular:tslint", "options": { "tsConfig": [ "e2e/tsconfig.e2e.json" ], "exclude": [ "**/node_modules/**" ] } } } } }, "defaultProject": "browser", "schematics": { "@schematics/angular:component": { "prefix": "app", "styleext": "scss" }, "@schematics/angular:directive": { "prefix": "app" } } } 

package.json 的package.json

 { "name": "myapp", "version": "3.0.0", "description": "myapp", "main": "server.js", "scripts": { "build:ssr": "npm run build:client-and-server-bundles && npm run webpack:server", "serve:ssr": "node server", "build:client-and-server-bundles": "ng build --prod && ng run browser:server", "webpack:server": "webpack --config webpack.server.config.js --progress --colors" }, "engines": { "node": "8.11.2", "npm": "6.0.1" }, "dependencies": { "@angular/animations": "6.0.2", "@angular/common": "6.0.2", "@angular/compiler": "6.0.2", "@angular/core": "6.0.2", "@angular/forms": "6.0.2", "@angular/http": "6.0.2", "@angular/platform-browser": "6.0.2", "@angular/platform-browser-dynamic": "6.0.2", "@angular/platform-server": "6.0.2", "@angular/router": "6.0.2", "@angular/upgrade": "6.0.2", "@angularclass/bootloader": "^1.0.1", "@ng-bootstrap/ng-bootstrap": "^1.0.0", "@ng-select/ng-select": "^0.32.0", "@ngtools/webpack": "^6.0.3", "@nguniversal/express-engine": "^6.0.0", "@nguniversal/module-map-ngfactory-loader": "^6.0.0", "@types/async": "^2.0.47", "@types/moment": "^2.13.0", "@types/uuid": "^3.4.3", "@uirouter/angular": "^1.0.1", "angular-elastic": "^2.5.1", "angular-filesize-filter": "^0.1.3", "angular-froala-wysiwyg": "^2.7.5", "angular-pipes": "^7.1.0", "angular-sortablejs": "^2.5.2", "angular2-busy": "^2.0.4", "angular2-cookie": "^1.2.6", "angular2-moment": "^1.8.0", "animate.css": "~3.5.2", "async": "~2.0.0-rc.5", "aws-sdk": "^2.235.1", "body-parser": "^1.18.2", "bootstrap": "^3.3.7", "chai": "^4.1.2", "chai-as-promised": "^7.1.1", "chai-jquery": "^2.0.0", "compression": "~1.6.2", "connect-gzip-static": "~1.0.0", "core-js": "^2.4.1", "domino": "^1.0.30", "dotenv": "^5.0.0", "ejs": "^2.6.1", "envify": "~3.4.1", "es6-promise": "^4.2.2", "express": "~4.14.0", "express-history-api-fallback": "^2.2.1", "express-sslify": "^1.2.0", "git-rev": "^0.2.1", "heroku-ssl-redirect": "0.0.4", "http-server": "~0.9.0", "httpbackend": "^2.0.0", "is-utf8": "^0.2.1", "jquery": "~3.1.1", "jquery-watch": "^1.21.0", "lodash": "~4.11.1", "lodash-move": "^1.1.1", "moment": "~2.15.1", "nconf": "~0.8.4", "ng-elastic": "^1.0.0-beta.5", "ng-file-upload": "~12.0.4", "ng-img-crop": "~0.2.0", "ng2-file-upload": "^1.3.0", "ng2-pnotify": "0.0.3", "ng2-search-filter": "^0.4.7", "ng4-validators": "^5.1.0", "ngx-color-picker": "^5.3.3", "ngx-cookie": "^3.0.1", "ngx-pagination": "^3.1.0", "ngx-textarea-autosize": "^1.1.1", "pnotify": "~3.0.0", "popup-tools": "^1.0.2", "protractor": "~5.3.0", "protractor-cucumber-framework": "^4.2.0", "request": "^2.85.0", "require-globify": "~1.4.1", "rxjs": "^6.1.0", "rxjs-compat": "^6.1.0", "sass-thematic": "^2.0.4", "selectize": "~0.12.4", "socket.io-client": "^2.0.4", "sortablejs": "^1.7.0", "striptags": "^3.1.1", "sweetalert2": "^7.10.0", "textangular": "~1.5.1", "thematic": "0.0.1", "ts-loader": "^4.1.0", "ts-node": "^4.1.0", "typescript": "2.7.2", "ui-select": "~0.18.1", "uuid": "^3.2.1", "zone.js": "^0.8.26" }, "devDependencies": { "@angular-devkit/build-angular": "~0.6.3", "@angular/cli": "6.0.3", "@angular/compiler-cli": "6.0.2", "@angular/language-service": "6.0.2", "@types/jasmine": "~2.8.3", "@types/jasminewd2": "~2.0.2", "@types/node": "~6.0.60", "codelyzer": "^4.0.1", "jasmine-core": "~2.8.0", "jasmine-spec-reporter": "~4.2.1", "karma": "~2.0.0", "karma-chrome-launcher": "~2.2.0", "karma-coverage-istanbul-reporter": "^1.2.1", "karma-jasmine": "~1.1.0", "karma-jasmine-html-reporter": "^0.2.2", "protractor": "~5.1.2", "ts-node": "~4.1.0", "tslint": "~5.9.1", "typescript": "2.7.2", "webpack-cli": "^2.1.3" } } 

You need to remove "bundleDependencies": "all" from angular.json file (under server -> options). 您需要从angular.json文件中删除"bundleDependencies": "all" (在server - > options下)。 Not sure why it's breaking, but it sure does fix the issue. 不知道为什么它会破裂,但它确实解决了这个问题。

I had the same problem and fixed it. 我有同样的问题并修复它。 The problem was in the angular.json file. 问题出在angular.json文件中。 Not sure what caused it. 不知道是什么造成的。 I used the angular.json from universal example and adjusted it to my project / portfolio. 我使用了通用示例中的angular.json并将其调整为我的项目/投资组合。 I also have reported this issue and provided an example of a working angular.json: 我也报告了这个问题并提供了一个工作angular.json的例子:

https://github.com/angular/universal/issues/1021 https://github.com/angular/universal/issues/1021

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM