开发中的 Angularjs:在另一个端口上使用服务
Posted
技术标签:
【中文标题】开发中的 Angularjs:在另一个端口上使用服务【英文标题】:Angularjs in development: using a service on another port 【发布时间】:2015-10-05 14:14:36 【问题描述】:我正在开发一个 angularjs 客户端,用于使用我在 Django 中编写的 RESTful 服务。我目前没有对服务进行任何开发,也不需要能够方便地更改它。
我确实想方便地更改 Angular 客户端。当我开发时,我想让服务通过127.0.0.1
上的 dockerized nginx 服务器或127.0.0.1:8000
上的 Django 开发服务器运行,两者都可以。默认情况下,grunt 在 127.0.0.1:9000
上为 Angular 应用程序提供服务,这意味着对我的服务的调用,例如 (coffeescript):
return $resource('api/logos/:id')
正在寻找127.0.0.1:9000/api/…
,但找不到。在开发过程中,如何剥离或更改 Angular 正在寻找其服务的端口号?
编辑:Gruntfile
按要求:
// Generated on 2015-03-05 using generator-angular 0.11.1
'use strict';
// # Globbing
// for performance reasons we're only matching one level down:
// 'test/spec/,*/*.js'
// use this if you want to recursively match all subfolders:
// 'test/spec/**/*.js'
module.exports = function (grunt)
// Load grunt tasks automatically
require('load-grunt-tasks')(grunt);
// Time how long tasks take. Can help when optimizing build times
require('time-grunt')(grunt);
// Configurable paths for the application
var appConfig =
app: require('./bower.json').appPath || 'app',
dist: 'dist'
;
// Define the configuration for all the tasks
grunt.initConfig(
// Project settings
yeoman: appConfig,
// Watches files for changes and runs tasks based on the changed files
watch:
bower:
files: ['bower.json'],
tasks: ['wiredep']
,
coffee:
files: ['<%= yeoman.app %>/scripts/,*/*.coffee,litcoffee,coffee.md'],
tasks: ['newer:coffee:dist']
,
coffeeTest:
files: ['test/spec/,*/*.coffee,litcoffee,coffee.md'],
tasks: ['newer:coffee:test', 'karma']
,
compass:
files: ['<%= yeoman.app %>/styles/,*/*.scss,sass'],
tasks: ['compass:server', 'autoprefixer']
,
gruntfile:
files: ['Gruntfile.js']
,
livereload:
options:
livereload: '<%= connect.options.livereload %>'
,
files: [
'<%= yeoman.app %>/,*/*.html',
'.tmp/styles/,*/*.css',
'.tmp/scripts/,*/*.js',
'<%= yeoman.app %>/images/,*/*.png,jpg,jpeg,gif,webp,svg'
]
,
// The actual grunt server settings
connect:
options:
port: 9000,
// Change this to '0.0.0.0' to access the server from outside.
hostname: '0.0.0.0',
livereload: 35729
,
livereload:
options:
open: false,
middleware: function (connect)
return [
connect.static('.tmp'),
connect().use(
'/bower_components',
connect.static('./bower_components')
),
connect().use(
'/app/styles',
connect.static('./app/styles')
),
connect.static(appConfig.app)
];
,
test:
options:
port: 9001,
middleware: function (connect)
return [
connect.static('.tmp'),
connect.static('test'),
connect().use(
'/bower_components',
connect.static('./bower_components')
),
connect.static(appConfig.app)
];
,
dist:
options:
open: true,
base: '<%= yeoman.dist %>'
,
// Make sure code styles are up to par and there are no obvious mistakes
jshint:
options:
jshintrc: '.jshintrc',
reporter: require('jshint-stylish')
,
all:
src: [
'Gruntfile.js'
]
,
// Empties folders to start fresh
clean:
dist:
files: [
dot: true,
src: [
'.tmp',
'<%= yeoman.dist %>/,*/*',
'!<%= yeoman.dist %>/.git,*/*'
]
]
,
server: '.tmp'
,
// Add vendor prefixed styles
autoprefixer:
options:
browsers: ['last 1 version']
,
server:
options:
map: true,
,
files: [
expand: true,
cwd: '.tmp/styles/',
src: ',*/*.css',
dest: '.tmp/styles/'
]
,
dist:
files: [
expand: true,
cwd: '.tmp/styles/',
src: ',*/*.css',
dest: '.tmp/styles/'
]
,
// Automatically inject Bower components into the app
wiredep:
app:
src: ['<%= yeoman.app %>/index.html'],
ignorePath: /\.\.\//
,
test:
devDependencies: true,
src: '<%= karma.unit.configFile %>',
ignorePath: /\.\.\//,
fileTypes:
coffee:
block: /(([\s\t]*)#\s*?bower:\s*?(\S*))(\n|\r|.)*?(#\s*endbower)/gi,
detect:
js: /'(.*\.js)'/gi,
coffee: /'(.*\.coffee)'/gi
,
replace:
js: '\'filePath\'',
coffee: '\'filePath\''
,
sass:
src: ['<%= yeoman.app %>/styles/,*/*.scss,sass'],
ignorePath: /(\.\.\/)1,2bower_components\//
,
// Compiles CoffeeScript to javascript
coffee:
options:
sourceMap: true,
sourceRoot: ''
,
dist:
files: [
expand: true,
cwd: '<%= yeoman.app %>/scripts',
src: ',*/*.coffee',
dest: '.tmp/scripts',
ext: '.js'
]
,
test:
files: [
expand: true,
cwd: 'test/spec',
src: ',*/*.coffee',
dest: '.tmp/spec',
ext: '.js'
]
,
// Compiles Sass to CSS and generates necessary files if requested
compass:
options:
sassDir: '<%= yeoman.app %>/styles',
cssDir: '.tmp/styles',
generatedImagesDir: '.tmp/images/generated',
imagesDir: '<%= yeoman.app %>/images',
javascriptsDir: '<%= yeoman.app %>/scripts',
fontsDir: '<%= yeoman.app %>/styles/fonts',
importPath: './bower_components',
httpImagesPath: '/images',
httpGeneratedImagesPath: '/images/generated',
httpFontsPath: '/styles/fonts',
relativeAssets: false,
assetCacheBuster: false,
raw: 'Sass::Script::Number.precision = 10\n'
,
dist:
options:
generatedImagesDir: '<%= yeoman.dist %>/images/generated'
,
server:
options:
sourcemap: true
,
// Renames files for browser caching purposes
filerev:
dist:
src: [
'<%= yeoman.dist %>/scripts/,*/*.js',
'<%= yeoman.dist %>/styles/,*/*.css',
'<%= yeoman.dist %>/images/,*/*.png,jpg,jpeg,gif,webp,svg',
'<%= yeoman.dist %>/styles/fonts/*'
]
,
// Reads HTML for usemin blocks to enable smart builds that automatically
// concat, minify and revision files. Creates configurations in memory so
// additional tasks can operate on them
useminPrepare:
html: '<%= yeoman.app %>/index.html',
options:
dest: '<%= yeoman.dist %>',
flow:
html:
steps:
js: ['concat', 'uglifyjs'],
css: ['cssmin']
,
post:
,
// Performs rewrites based on filerev and the useminPrepare configuration
usemin:
html: ['<%= yeoman.dist %>/,*/*.html'],
css: ['<%= yeoman.dist %>/styles/,*/*.css'],
options:
assetsDirs: [
'<%= yeoman.dist %>',
'<%= yeoman.dist %>/images',
'<%= yeoman.dist %>/styles'
]
,
// The following *-min tasks will produce minified files in the dist folder
// By default, your `index.html`'s <!-- Usemin block --> will take care of
// minification. These next options are pre-configured if you do not wish
// to use the Usemin blocks.
// cssmin:
// dist:
// files:
// '<%= yeoman.dist %>/styles/main.css': [
// '.tmp/styles/,*/*.css'
// ]
//
//
// ,
// uglify:
// dist:
// files:
// '<%= yeoman.dist %>/scripts/scripts.js': [
// '<%= yeoman.dist %>/scripts/scripts.js'
// ]
//
//
// ,
// concat:
// dist:
// ,
imagemin:
dist:
files: [
expand: true,
cwd: '<%= yeoman.app %>/images',
src: ',*/*.png,jpg,jpeg,gif',
dest: '<%= yeoman.dist %>/images'
]
,
svgmin:
dist:
files: [
expand: true,
cwd: '<%= yeoman.app %>/images',
src: ',*/*.svg',
dest: '<%= yeoman.dist %>/images'
]
,
htmlmin:
dist:
options:
collapseWhitespace: true,
conservativeCollapse: true,
collapseBooleanAttributes: true,
removeCommentsFromCDATA: true,
removeOptionalTags: true
,
files: [
expand: true,
cwd: '<%= yeoman.dist %>',
src: ['*.html', 'views/,*/*.html'],
dest: '<%= yeoman.dist %>'
]
,
// ng-annotate tries to make the code safe for minification automatically
// by using the Angular long form for dependency injection.
ngAnnotate:
dist:
files: [
expand: true,
cwd: '.tmp/concat/scripts',
src: '*.js',
dest: '.tmp/concat/scripts'
]
,
// Replace Google CDN references
cdnify:
dist:
html: ['<%= yeoman.dist %>/*.html']
,
// Copies remaining files to places other tasks can use
copy:
dist:
files: [
expand: true,
dot: true,
cwd: '<%= yeoman.app %>',
dest: '<%= yeoman.dist %>',
src: [
'*.ico,png,txt',
'.htaccess',
'*.html',
'views/,*/*.html',
'images/,*/*.webp',
'styles/fonts/,*/*.*'
]
,
expand: true,
cwd: '.tmp/images',
dest: '<%= yeoman.dist %>/images',
src: ['generated/*']
,
expand: true,
cwd: '.',
src: 'bower_components/bootstrap-sass-official/assets/fonts/bootstrap/*',
dest: '<%= yeoman.dist %>'
]
,
styles:
expand: true,
cwd: '<%= yeoman.app %>/styles',
dest: '.tmp/styles/',
src: ',*/*.css'
,
// Run some tasks in parallel to speed up the build process
concurrent:
server: [
'coffee:dist',
'compass:server'
],
test: [
'coffee',
'compass'
],
dist: [
'coffee',
'compass:dist',
'imagemin',
'svgmin'
]
,
// Test settings
karma:
unit:
configFile: 'test/karma.conf.coffee',
singleRun: true
);
grunt.registerTask('serve', 'Compile then start a connect web server', function (target)
if (target === 'dist')
return grunt.task.run(['build', 'connect:dist:keepalive']);
grunt.task.run([
'clean:server',
'wiredep',
'concurrent:server',
'autoprefixer:server',
'connect:livereload',
'watch'
]);
);
grunt.registerTask('server', 'DEPRECATED TASK. Use the "serve" task instead', function (target)
grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.');
grunt.task.run(['serve:' + target]);
);
grunt.registerTask('test', [
'clean:server',
'wiredep',
'concurrent:test',
'autoprefixer',
'connect:test',
'karma'
]);
grunt.registerTask('build', [
'clean:dist',
'wiredep',
'useminPrepare',
'concurrent:dist',
'autoprefixer',
'concat',
'ngAnnotate',
'copy:dist',
'cdnify',
'cssmin',
'uglify',
'filerev',
'usemin',
'htmlmin'
]);
grunt.registerTask('default', [
'newer:jshint',
'test',
'build'
]);
;
【问题讨论】:
您使用哪个 Grunt 插件来提供文件?在问题中包含相关配置(Gruntfile)也可能会有所帮助。 @NikosParaskevopoulos 我正在使用 yeoman 角度生成器的标准配置,但我已将主机更改为 0.0.0.0,因为 grunt 也在 docker 容器中工作。我已经编辑了问题以包含 Gruntfile。 【参考方案1】:更简单的方法是在服务上启用CORS。由于您的服务使用的是 Django,您应该可以使用 Django CORS headers app。
使用 pip 安装它,然后将 corsheaders
添加到您安装的应用程序中。接下来,在您的设置中添加 CORS 中间件before Django 的常用中间件,如下所示:
MIDDLEWARE_CLASSES = (
...
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
...
)
最后,再次在 Django 设置中将 Angular 应用程序所在的端口列入白名单,如下所示:
CORS_ORIGIN_WHITELIST = (
'localhost:9000' # for example. Your port may vary.
)
在角度方面,您需要在开发过程中为您的服务提供完整路径,否则端口差异会导致问题。
【讨论】:
【参考方案2】:我也遇到过类似的问题,我就是这样解决的:
拦截器修改 API 调用的 URL:
angular.module(...).config(['$httpProvider', function($httpProvider)
$httpProvider.interceptors.push(['env', function(env)
return
'request': function(config)
if( config.url.indexOf('/api/') === 0 )
config.url = env.apiContextPath + config.url;
return config;
;
]);
]);
您可能需要调整 indexOf(...)
部分,但您大致了解。阅读here 了解拦截器。
env
服务持有应用程序环境 配置,即本地开发、开发服务器、生产等不同。我在 Grunt 中使用grunt-ng-constant 生成它有很多方法可以做到这一点 - 此处不详述。
最后你必须设置grunt-connect
才能使用代理。免责声明:我的配置与此略有不同,因此虽然总体思路可能是正确的,但有些细节可能需要调整!
您需要grunt-connect-proxy。简而言之,只需按照他们文档中的步骤操作即可:
将代理配置添加到connect:livereload
将代理中间件添加到您的中间件(我相信最好先)
livereload:
options:
open: false,
middleware: function (connect)
return [
// ADDED PROXY MIDDLEWARE HERE
require('grunt-connect-proxy/lib/utils').proxyRequest,
connect.static('.tmp'),
connect().use(
'/bower_components',
connect.static('./bower_components')
),
connect().use(
'/app/styles',
connect.static('./app/styles')
),
connect.static(appConfig.app)
];
,
proxies: [
context: '/api',
host: 'localhost', // the host serving your API
port: 8000 // again the port of your API server
]
,
将configureProxy任务添加到服务器任务中:
grunt.registerTask('serve', 'Compile then start a connect web server', function (target)
if (target === 'dist')
return grunt.task.run(['build', 'connect:dist:keepalive']);
grunt.task.run([
'clean:server',
'wiredep',
'concurrent:server',
'autoprefixer:server',
'configureProxies:livereload', // HERE
'connect:livereload',
'watch'
]);
);
【讨论】:
这看起来像我需要的。我现在离开了我的系统,所以我需要一段时间才能试用它,但一旦我开始工作,我会接受,并根据需要进行编辑。以上是关于开发中的 Angularjs:在另一个端口上使用服务的主要内容,如果未能解决你的问题,请参考以下文章
Netflix Zuul 在一个端口上,Hystrix Dashboard 在另一个端口上
如何使用 AngularJS 访问位于不同 js 文件中的变量数据