我是AngularJS的新手,请原谅我,如果这是显而易见的,但我正在寻找能够回答这个棘手问题的人。我正在实现一个应用程序,需要将一些参数传递给特定视图以显示有关书籍的详细信息。基本上我希望能够使用以下路由表达式:
bookApp.config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/catalog', {
templateUrl: 'cataloglist.htm',
controller: 'catCtrl'
}).
when('/book/:title/:chapter', {
template: 'chapterdetail.htm',
controller: 'chapterCtrl'
}).
otherwise({
template: 'oops ... do not understand that route',
});
}]);
表达式/book/:title/:chapter
应该允许我传入书名的名称。我希望能够通过任何一本书的任何标题。为了确保正确分隔内容,我将对标题值进行URL编码,以便在编码值中没有斜杠,并且该值将由斜杠字符清楚地分隔。这是构造包含值的URL的常规方法。
问题是存在包含斜杠字符的书名(例如The 3/5 solution
)这是以The+3%2F5+Solution
编码的URL。所以可以构建这样的URL:
/app/#/book/The+3%2F5+Solution/The%20Beginning
然而,我的经验似乎表明,在将其分解为参数之前,整个值都是URL解码的!这意味着任何带有斜杠的数据值将被误解释为两个值,并且路径参数的模式匹配被破坏,并且只传递值的前半部分。 ,章节中也可能有一个斜线。
如果我正在制作REST服务,我会对该值进行URL编码,并且在每个片段被解码之前,URL将被解析为片段。例如,我可以在URL中使用查询参数:
app.jsp?title=The+3%2F5+Solution&chapter=The%20Beginning
这将正常工作。使用URL编码,我可以在标题中传递任何字符串值。我本来希望路由参数可以做同样的事情......但我已经提到过我对AngularJS很新。
在确定碎片看起来像一个非常严重的错误之前,将%2F
解码为斜线。显然,您根本无法将带斜杠的值作为路由参数传递。 我在这里遗漏了什么吗?有什么方法可以让我安全地传递一个带有任何可能角色的书名(以及带有任意字符的章节标题)作为路线参数?
答案 0 :(得分:11)
看一下棱角分明的route.js
sourcecode,就有可能实现你想要的东西:
path
可以包含以冒号开头并以星号结尾的命名组: e.g。:name*
。当路线匹配时,所有字符都热切地存储在给定$routeParams
下的name
中。
例如,/color/:color/largecode/:largecode*\/edit
之类的路线会匹配/color/brown/largecode/code/with/slashes/edit
并提取:
color: brown
largecode: code/with/slashes
。
注意示例中:largecode*\
param末尾的反斜杠。它不存在于以星号结尾的命名组的描述中,但它在示例中。我没有对此进行测试,也不知道是否需要反斜杠,因此请考虑它可能/可能不需要。
因此,您的问题的解决方案将如下所示:
/book/:title*/chapter/:chapter*
注意添加的/chapter/
部分。为了区分两个命名组,需要它。如果您只使用/book/:title*/:chapter*
,则所有内容都属于:title*
命名组。但是,如果您使用/:title*/chapter/:chapter*
,则angular知道:title*
命名组何时结束:何时在路由中遇到/chapter/
。 /chapter/
之后的所有内容都属于:chapter*
命名组
答案 1 :(得分:3)
由于上述行为,似乎无法使用URL编码。这意味着您必须使用代表完整Unicode字符集的编码,而不使用斜杠或百分号或加号,也不得使用任何其他可能导致URL解码器认为存在要解码的编码值的编码。
该值的BASE 64编码将起到作用,解决方案似乎是定义以下过滤器:
bookApp.filter('btoa', function() {
return function (str) {
return window.btoa(encodeURIComponent(escape(str)));
}
});
bookApp.filter('atob', function() {
return function(str) {
return unescape(decodeURIComponent(window.atob(str)));
}
});
这允许您编写如下代码:
<a href="#/book/{{title | atob}}/{{chapter | atob}}">See Details</a>
然后,在接收方,您调用btoa将值重新用于您想要的任何目的。然后将值The 3/5 solution
编码为VGhlJTI1MjAzJTJGNSUyNTIwc29sdXRpb24=
,它始终是路由参数模式识别器中的单个参数,并且会被精确地解码回已发送的值。
完全支持语言。一本名为奥の細道
的书籍将被编码为JTI1dTU5NjUlMjV1MzA2RSUyNXU3RDMwJTI1dTkwNTM=
- 再次避免任何可能破坏该值的问题。
额外的encodeURIComponent
和escape
调用是为了欺骗JS将unicode字符串转换为UTF-8编码,然后由window.atob函数进行转换,否则会失败某些高阶Unicode字符。有关更多信息,请访问Mozilla Developer Network
答案 2 :(得分:0)
when(&#39; / catalog /:book&#39;,{ templateUrl:&#39; cataloglist.htm&#39;, 控制器:&#39; catCtrl&#39; })
如果您的路线参数书已加密,则可能包含&#39; /&#39; (反斜杠字符),为了在浏览器中转换正确的可执行文件,你必须使用encodeURIComponent来转换&#39; /&#39;到&#39;%2F&#39;。
$ window.location =&#39; / catalog /&#39; + encodeURIComponent(Solution / The%20Beginning);
答案 3 :(得分:0)
相关的github问题:https://github.com/angular/angular.js/issues/10479 解决方法是对参数进行两次编码:
encodeURIComponent(encodeURIComponent("The 3/5 solution"))