使用Angular 2路由实现自定义URL编码(使用加号代替空格)

11

我正在使用Angular 2的路由器来更新搜索应用程序中URL的查询参数。我试图用+号替换查询中的空格,但是+号被编码了。例如:

this.router.navigatebyUrl('?q=one+two');

使用"?q=one%2Btwo"填充URL。

查看Angular 2的源代码,发现路由器将URL转换为UrlTree ,并使用encodeURIComponent()对URL进行编码。因此,无法防止默认的编码。

我的当前流程是通过执行navigateByUrl更改路由,并使用以下方法监听更改:

this.routeSubscription = this.route.queryParams.subscribe((params: any) => {
  this.term = (params.q ? params.q : '');
});

是否有一种替代方法来处理查询参数,可以允许我使用自己的 URL 编码策略?


可能是angular 2禁用URL编码的重复问题。 - jigar gala
3个回答

24

我成功解决了我的问题。您可以通过实现UrlSerializer类来创建自定义URL序列化器。

自定义URL序列化器

像这样创建一个自定义URL序列化器:

@Injectable()
export class CustomUrlSerializer implements UrlSerializer {

    constructor(private defaultUrlSerializer: DefaultUrlSerializer){}

    parse(url: string): UrlTree {
        // Custom code here
    }

    serialize(tree: UrlTree): string {
        // Custom code here
    }
}

然后,你只需要使用CustomUrlSerializer代替UrlSerializer,并将其放置在AppModule提供商数组中,在导入两个序列化程序之后。

providers: [
    { provide: UrlSerializer, useClass: CustomUrlSerializer },
       DefaultUrlSerializer
    ...
]

现在,当您调用router.navigate或router.navigateByUrl时,它将使用您的自定义序列化程序进行解析和序列化。

使用加号作为空格

要将加号解析为空格:

parse(url: string): UrlTree {
    // Change plus signs to encoded spaces
    url = url.replace(/\+/g, '%20');
    // Use the default serializer that you can import to just do the 
    // default parsing now that you have fixed the url.
    return this.defaultUrlSerializer.parse(url)  
}

并且用于序列化:

serialize(tree: UrlTree): string {
    // Use the default serializer to create a url and replace any spaces with + signs
    return this.defaultUrlSerializer.serialize(tree).replace(/%20/g, '+');
}

DefaultUrlSerializer


4
有人遇到了“ERROR in Invalid provider for undefined. useClass cannot be null.”这个错误吗? - koppor
我也遇到了这个问题。我在这个问题下添加了一个答案,解释了我的解决方法。 - Aaron Scherbing
当我在使用加号作为空格时,刷新页面会出现404错误。在将我的Angular项目上传到IIS后,在本地主机上运行良好。有人能提供解决建议吗? - Darshana
我在Angular 9.1中尝试了这个解决方案,但它抱怨说它不知道this.defaultSerializer。通过将implements UrlSerializer替换为extends DefaultUrlSerializer,并将this.defaultUrlSerializer.parse替换为this.parse以及将this.defaultSerializer.serialize替换为this.serialize,问题得到了解决。--问题的原因似乎是UrlSerializer是一个接口,因此不包含该方法的实现。 - Olli

6

我遇到了一个指定自定义提供程序的问题。显然,在使用--prod标志进行编译时存在循环依赖,导致出现以下错误文本:useClass cannot by null.这是我解决该错误的方法:

在AppModule中,定义以下内容:

const customUrlSerializer = new CustomUrlSerializer();
const CustomUrlSerializerProvider = {
    provide: UrlSerializer,
    useValue: customUrlSerializer
};

然后在providers数组中添加您上面指定的提供程序。

...
providers: [CustomUrlSerializerProvider]
...

0

我在 Angular 9.1 中尝试了 @Noah 的解决方案,以避免 ? 被替换为 %3F

然而,这个并没有起作用

class CustomUrlSerializer implements UrlSerializer {
  parse(url: string): UrlTree {
    return this.defaultSerializer.parse(url)  
  }

  serialize(tree: UrlTree): string {
    return this.defaultSerializer.serialize(tree).replace(/%3F/g, '?');
  }
}

Angular 报错,错误信息如下

client:159 src/app/app.module.ts:36:17 - error TS2339: Property 'defaultSerializer' does not exist on type 'CustomUrlSerializer'.

以下代码对我而言是有效的

class CustomUrlSerializer extends DefaultUrlSerializer {
  parse(url: string): UrlTree {
    return super.parse(url)  
  }

  serialize(tree: UrlTree): string {
    return super.serialize(tree).replace(/%20/g, '+');
  }
}

我已经替换了:

implements UrlSerializer --> extends DefaultUrlSerializer
this.defaultSerializer   --> super

注意:我已经删除了以下的反向翻译,因为它在路由URL之前将?替换为%3F,但在这种情况下我们希望保留它。
  parse(url: string): UrlTree {
    url = url.replace(/\?/g, '%3F'); // <--- removed
    ...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接